diff --git a/go.mod b/go.mod index fcefdd7f1a..f204303dff 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/opencloud-eu/opencloud -go 1.24.1 +go 1.24.6 require ( dario.cat/mergo v1.0.2 @@ -63,7 +63,7 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo/v2 v2.25.3 github.com/onsi/gomega v1.38.2 - github.com/open-policy-agent/opa v1.6.0 + github.com/open-policy-agent/opa v1.8.0 github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 github.com/opencloud-eu/reva/v2 v2.38.1-0.20250922152322-476bb1f0070a github.com/opensearch-project/opensearch-go/v4 v4.5.0 @@ -179,6 +179,7 @@ require ( github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set v1.8.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/ristretto v0.2.0 // indirect github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect @@ -257,6 +258,12 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc/v3 v3.0.0 // indirect + github.com/lestrrat-go/jwx/v3 v3.0.10 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect + github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/libregraph/oidc-go v1.1.0 // indirect github.com/longsleep/go-metrics v1.0.0 // indirect github.com/longsleep/rndm v1.2.0 // indirect @@ -318,10 +325,11 @@ require ( github.com/rs/xid v1.6.0 // indirect github.com/russellhaering/goxmldsig v1.5.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/segmentio/asm v1.2.0 // indirect github.com/segmentio/kafka-go v0.4.49 // indirect github.com/segmentio/ksuid v1.0.4 // indirect github.com/sercand/kuberesolver/v5 v5.1.1 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/sergi/go-diff v1.4.0 // indirect github.com/sethvargo/go-diceware v0.5.0 // indirect github.com/sethvargo/go-password v0.3.1 // indirect github.com/shamaton/msgpack/v2 v2.3.1 // indirect @@ -333,7 +341,7 @@ require ( github.com/spf13/pflag v1.0.9 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/studio-b12/gowebdav v0.9.0 // indirect - github.com/tchap/go-patricia/v2 v2.3.2 // indirect + github.com/tchap/go-patricia/v2 v2.3.3 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tinylib/msgp v1.3.0 // indirect @@ -341,7 +349,8 @@ require ( github.com/tklauser/numcpus v0.8.0 // indirect github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect github.com/trustelem/zxcvbn v1.0.1 // indirect - github.com/vektah/gqlparser/v2 v2.5.28 // indirect + github.com/valyala/fastjson v1.6.4 // indirect + github.com/vektah/gqlparser/v2 v2.5.30 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/wk8/go-ordered-map v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect @@ -374,7 +383,7 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 diff --git a/go.sum b/go.sum index 0c4facc23c..fe69cfdd4a 100644 --- a/go.sum +++ b/go.sum @@ -275,11 +275,13 @@ github.com/davidbyttow/govips/v2 v2.16.0 h1:1nH/Rbx8qZP1hd+oYL9fYQjAnm1+KorX9s07 github.com/davidbyttow/govips/v2 v2.16.0/go.mod h1:clH5/IDVmG5eVyc23qYpyi7kmOT0B/1QNTKtci4RkyM= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/deepmap/oapi-codegen v1.3.11/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= -github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs= +github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w= github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= @@ -743,6 +745,18 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc= github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8= +github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= +github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc/v3 v3.0.0 h1:nZUx/zFg5uc2rhlu1L1DidGr5Sj02JbXvGSpnY4LMrc= +github.com/lestrrat-go/httprc/v3 v3.0.0/go.mod h1:k2U1QIiyVqAKtkffbg+cUmsyiPGQsb9aAfNQiNFuQ9Q= +github.com/lestrrat-go/jwx/v3 v3.0.10 h1:XuoCBhZBncRIjMQ32HdEc76rH0xK/Qv2wq5TBouYJDw= +github.com/lestrrat-go/jwx/v3 v3.0.10/go.mod h1:kNMedLgTpHvPJkK5EMVa1JFz+UVyY2dMmZKu3qjl/Pk= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= +github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/libregraph/idm v0.5.0 h1:tDMwKbAOZzdeDYMxVlY5PbSqRKO7dbAW9KT42A51WSk= github.com/libregraph/idm v0.5.0/go.mod h1:BGMwIQ/6orJSPVzJ1x6kgG2JyG9GY05YFmbsnaD80k0= github.com/libregraph/lico v0.66.0 h1:7T6fD1YF0Ep9n0g4KN6dvWHTlDC3awrQpgsP5GdYCF4= @@ -910,8 +924,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= -github.com/open-policy-agent/opa v1.6.0 h1:/S/cnNQJ2MUMNzizHPbisTWBHowmLkPrugY5jjkPlRQ= -github.com/open-policy-agent/opa v1.6.0/go.mod h1:zFmw4P+W62+CWGYRDDswfVYSCnPo6oYaktQnfIaRFC4= +github.com/open-policy-agent/opa v1.8.0 h1:4JdYuZcANeUF1v/87NGpirocpaZzJA0PcuL7xfmsMNM= +github.com/open-policy-agent/opa v1.8.0/go.mod h1:vOVZuIJQISnaYcZtQ58yTDkVCp1FmGPwK43pO9qPDqM= github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M= github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY= github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI= @@ -1053,14 +1067,16 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/kafka-go v0.4.49 h1:GJiNX1d/g+kG6ljyJEoi9++PUMdXGAxb7JGPiDCuNmk= github.com/segmentio/kafka-go v0.4.49/go.mod h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= +github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sethvargo/go-diceware v0.5.0 h1:exrQ7GpaBo00GqRVM1N8ChXSsi3oS7tjQiIehsD+yR0= github.com/sethvargo/go-diceware v0.5.0/go.mod h1:Lg1SyPS7yQO6BBgTN5r4f2MUDkqGfLWsOjHPY0kA8iw= github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= @@ -1133,8 +1149,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tchap/go-patricia/v2 v2.3.2 h1:xTHFutuitO2zqKAQ5rCROYgUb7Or/+IC3fts9/Yc7nM= -github.com/tchap/go-patricia/v2 v2.3.2/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc= +github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= @@ -1177,10 +1193,12 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= +github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/vektah/gqlparser/v2 v2.5.28 h1:bIulcl3LF69ba6EiZVGD88y4MkM+Jxrf3P2MX8xLRkY= -github.com/vektah/gqlparser/v2 v2.5.28/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= +github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE= +github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= @@ -1254,8 +1272,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZF go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= @@ -1770,7 +1788,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= stash.kopano.io/kgol/rndm v1.1.2 h1:vriNehb5NuglfGqZPkgeFr2Y5AjXtQCF4vEl4kqc6nc= stash.kopano.io/kgol/rndm v1.1.2/go.mod h1:CBvpAHlOwyu/XipxfLGk02UN3K3P6hQ8E2JoTbNWfJU= diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE new file mode 100644 index 0000000000..fdf6d88225 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/LICENSE @@ -0,0 +1,17 @@ +ISC License + +Copyright (c) 2013-2017 The btcsuite developers +Copyright (c) 2015-2024 The Decred developers +Copyright (c) 2017 The Lightning Network Developers + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md new file mode 100644 index 0000000000..b84bcdb77d --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/README.md @@ -0,0 +1,72 @@ +secp256k1 +========= + +[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions) +[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) +[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4) + +Package secp256k1 implements optimized secp256k1 elliptic curve operations. + +This package provides an optimized pure Go implementation of elliptic curve +cryptography operations over the secp256k1 curve as well as data structures and +functions for working with public and private secp256k1 keys. See +https://www.secg.org/sec2-v2.pdf for details on the standard. + +In addition, sub packages are provided to produce, verify, parse, and serialize +ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme +specific to Decred) signatures. See the README.md files in the relevant sub +packages for more details about those aspects. + +An overview of the features provided by this package are as follows: + +- Private key generation, serialization, and parsing +- Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys +- Specialized types for performing optimized and constant time field operations + - `FieldVal` type for working modulo the secp256k1 field prime + - `ModNScalar` type for working modulo the secp256k1 group order +- Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) +- Point decompression from a given x coordinate +- Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing algorithms + +It also provides an implementation of the Go standard library `crypto/elliptic` +`Curve` interface via the `S256` function so that it may be used with other +packages in the standard library such as `crypto/tls`, `crypto/x509`, and +`crypto/ecdsa`. However, in the case of ECDSA, it is highly recommended to use +the `ecdsa` sub package of this package instead since it is optimized +specifically for secp256k1 and is significantly faster as a result. + +Although this package was primarily written for dcrd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use optimized secp256k1 elliptic curve cryptography. + +Finally, a comprehensive suite of tests is provided to provide a high level of +quality assurance. + +## secp256k1 use in Decred + +At the time of this writing, the primary public key cryptography in widespread +use on the Decred network used to secure coins is based on elliptic curves +defined by the secp256k1 domain parameters. + +## Installation and Updating + +This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module. +Use the standard go tooling for working with modules to incorporate it. + +## Examples + +* [Encryption](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#example-package-EncryptDecryptMessage) + Demonstrates encrypting and decrypting a message using a shared key derived + through ECDHE. + +## License + +Package secp256k1 is licensed under the [copyfree](http://copyfree.org) ISC +License. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go new file mode 100644 index 0000000000..bb0b41fda1 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/compressedbytepoints.go @@ -0,0 +1,18 @@ +// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// Auto-generated file (see genprecomps.go) +// DO NOT EDIT + +var compressedBytePoints = "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" + +// Set accessor to a real function. +func init() { + compressedBytePointsFn = func() string { + return compressedBytePoints + } +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go new file mode 100644 index 0000000000..6d6d669f19 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve.go @@ -0,0 +1,1310 @@ +// Copyright (c) 2015-2024 The Decred developers +// Copyright 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "encoding/hex" + "math/bits" +) + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) +// +// [BRID]: On Binary Representations of Integers with Digits -1, 0, 1 +// (Prodinger, Helmut) +// +// [STWS]: Secure-TWS: Authenticating Node to Multi-user Communication in +// Shared Sensor Networks (Oliveira, Leonardo B. et al) + +// All group operations are performed using Jacobian coordinates. For a given +// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1) +// where x = x1/z1^2 and y = y1/z1^3. + +// hexToFieldVal converts the passed hex string into a FieldVal and will panic +// if there is an error. This is only provided for the hard-coded constants so +// errors in the source code can be detected. It will only (and must only) be +// called with hard-coded values. +func hexToFieldVal(s string) *FieldVal { + b, err := hex.DecodeString(s) + if err != nil { + panic("invalid hex in source file: " + s) + } + var f FieldVal + if overflow := f.SetByteSlice(b); overflow { + panic("hex in source file overflows mod P: " + s) + } + return &f +} + +// hexToModNScalar converts the passed hex string into a ModNScalar and will +// panic if there is an error. This is only provided for the hard-coded +// constants so errors in the source code can be detected. It will only (and +// must only) be called with hard-coded values. +func hexToModNScalar(s string) *ModNScalar { + var isNegative bool + if len(s) > 0 && s[0] == '-' { + isNegative = true + s = s[1:] + } + if len(s)%2 != 0 { + s = "0" + s + } + b, err := hex.DecodeString(s) + if err != nil { + panic("invalid hex in source file: " + s) + } + var scalar ModNScalar + if overflow := scalar.SetByteSlice(b); overflow { + panic("hex in source file overflows mod N scalar: " + s) + } + if isNegative { + scalar.Negate() + } + return &scalar +} + +var ( + // The following constants are used to accelerate scalar point + // multiplication through the use of the endomorphism: + // + // φ(Q) ⟼ λ*Q = (β*Q.x mod p, Q.y) + // + // See the code in the deriveEndomorphismParams function in genprecomps.go + // for details on their derivation. + // + // Additionally, see the scalar multiplication function in this file for + // details on how they are used. + endoNegLambda = hexToModNScalar("-5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72") + endoBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee") + endoNegB1 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c3") + endoNegB2 = hexToModNScalar("-3086d221a7d46bcde86c90e49284eb15") + endoZ1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f") + endoZ2 = hexToModNScalar("e4437ed6010e88286f547fa90abfe4c4221208ac9df506c6") + + // Alternatively, the following parameters are valid as well, however, + // benchmarks show them to be about 2% slower in practice. + // endoNegLambda = hexToModNScalar("-ac9c52b33fa3cf1f5ad9e3fd77ed9ba4a880b9fc8ec739c2e0cfc810b51283ce") + // endoBeta = hexToFieldVal("851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40") + // endoNegB1 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb15") + // endoNegB2 = hexToModNScalar("-114ca50f7a8e2f3f657c1108d9d44cfd8") + // endoZ1 = hexToModNScalar("114ca50f7a8e2f3f657c1108d9d44cfd95fbc92c10fddd145") + // endoZ2 = hexToModNScalar("3086d221a7d46bcde86c90e49284eb153daa8a1471e8ca7f") +) + +// JacobianPoint is an element of the group formed by the secp256k1 curve in +// Jacobian projective coordinates and thus represents a point on the curve. +type JacobianPoint struct { + // The X coordinate in Jacobian projective coordinates. The affine point is + // X/z^2. + X FieldVal + + // The Y coordinate in Jacobian projective coordinates. The affine point is + // Y/z^3. + Y FieldVal + + // The Z coordinate in Jacobian projective coordinates. + Z FieldVal +} + +// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z +// coordinates. +func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint { + var p JacobianPoint + p.X.Set(x) + p.Y.Set(y) + p.Z.Set(z) + return p +} + +// Set sets the Jacobian point to the provided point. +func (p *JacobianPoint) Set(other *JacobianPoint) { + p.X.Set(&other.X) + p.Y.Set(&other.Y) + p.Z.Set(&other.Z) +} + +// ToAffine reduces the Z value of the existing point to 1 effectively +// making it an affine coordinate in constant time. The point will be +// normalized. +func (p *JacobianPoint) ToAffine() { + // Inversions are expensive and both point addition and point doubling + // are faster when working with points that have a z value of one. So, + // if the point needs to be converted to affine, go ahead and normalize + // the point itself at the same time as the calculation is the same. + var zInv, tempZ FieldVal + zInv.Set(&p.Z).Inverse() // zInv = Z^-1 + tempZ.SquareVal(&zInv) // tempZ = Z^-2 + p.X.Mul(&tempZ) // X = X/Z^2 (mag: 1) + p.Y.Mul(tempZ.Mul(&zInv)) // Y = Y/Z^3 (mag: 1) + p.Z.SetInt(1) // Z = 1 (mag: 1) + + // Normalize the x and y values. + p.X.Normalize() + p.Y.Normalize() +} + +// EquivalentNonConst returns whether or not two Jacobian points represent the +// same affine point in *non-constant* time. +func (p *JacobianPoint) EquivalentNonConst(other *JacobianPoint) bool { + // Since the point at infinity is the identity element for the group, note + // that P = P + ∞ trivially implies that P - P = ∞. + // + // Use that fact to determine if the points represent the same affine point. + var result JacobianPoint + result.Set(p) + result.Y.Normalize().Negate(1).Normalize() + AddNonConst(&result, other, &result) + return (result.X.IsZero() && result.Y.IsZero()) || result.Z.IsZero() +} + +// addZ1AndZ2EqualsOne adds two Jacobian points that are already known to have +// z values of 1 and stores the result in the provided result param. That is to +// say result = p1 + p2. It performs faster addition than the generic add +// routine since less arithmetic is needed due to the ability to avoid the z +// value multiplications. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ1AndZ2EqualsOne(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl + // + // In particular it performs the calculations using the following: + // H = X2-X1, HH = H^2, I = 4*HH, J = H*I, r = 2*(Y2-Y1), V = X1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = 2*H + // + // This results in a cost of 4 field multiplications, 2 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1 := &p1.X, &p1.Y + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. + if x1.Equals(x2) { + if y1.Equals(y2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, i, j, r, v FieldVal + var negJ, neg2V, negX3 FieldVal + h.Set(x1).Negate(1).Add(x2) // H = X2-X1 (mag: 3) + i.SquareVal(&h).MulInt(4) // I = 4*H^2 (mag: 4) + j.Mul2(&h, &i) // J = H*I (mag: 1) + r.Set(y1).Negate(1).Add(y2).MulInt(2) // r = 2*(Y2-Y1) (mag: 6) + v.Mul2(x1, &i) // V = X1*I (mag: 1) + negJ.Set(&j).Negate(1) // negJ = -J (mag: 2) + neg2V.Set(&v).MulInt(2).Negate(2) // neg2V = -(2*V) (mag: 3) + x3.Set(&r).Square().Add(&negJ).Add(&neg2V) // X3 = r^2-J-2*V (mag: 6) + negX3.Set(x3).Negate(6) // negX3 = -X3 (mag: 7) + j.Mul(y1).MulInt(2).Negate(2) // J = -(2*Y1*J) (mag: 3) + y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4) + z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addZ1EqualsZ2 adds two Jacobian points that are already known to have the +// same z value and stores the result in the provided result param. That is to +// say result = p1 + p2. It performs faster addition than the generic add +// routine since less arithmetic is needed due to the known equivalence. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ1EqualsZ2(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using a slightly modified version + // of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-zadd-2007-m + // + // In particular it performs the calculations using the following: + // A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B + // X3 = D-E-F, Y3 = C*(E-X3)-Y1*(F-E), Z3 = Z1*A + // + // This results in a cost of 5 field multiplications, 2 field squarings, + // 9 field additions, and 0 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. + if x1.Equals(x2) { + if y1.Equals(y2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var a, b, c, d, e, f FieldVal + var negX1, negY1, negE, negX3 FieldVal + negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2) + negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2) + a.Set(&negX1).Add(x2) // A = X2-X1 (mag: 3) + b.SquareVal(&a) // B = A^2 (mag: 1) + c.Set(&negY1).Add(y2) // C = Y2-Y1 (mag: 3) + d.SquareVal(&c) // D = C^2 (mag: 1) + e.Mul2(x1, &b) // E = X1*B (mag: 1) + negE.Set(&e).Negate(1) // negE = -E (mag: 2) + f.Mul2(x2, &b) // F = X2*B (mag: 1) + x3.Add2(&e, &f).Negate(2).Add(&d) // X3 = D-E-F (mag: 4) + negX3.Set(x3).Negate(4) // negX3 = -X3 (mag: 5) + y3.Set(y1).Mul(f.Add(&negE)).Negate(1) // Y3 = -(Y1*(F-E)) (mag: 2) + y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 3) + z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addZ2EqualsOne adds two Jacobian points when the second point is already +// known to have a z value of 1 (and the z value for the first point is not 1) +// and stores the result in the provided result param. That is to say result = +// p1 + p2. It performs faster addition than the generic add routine since +// less arithmetic is needed due to the ability to avoid multiplications by the +// second point's z value. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ2EqualsOne(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + // + // In particular it performs the calculations using the following: + // Z1Z1 = Z1^2, U2 = X2*Z1Z1, S2 = Y2*Z1*Z1Z1, H = U2-X1, HH = H^2, + // I = 4*HH, J = H*I, r = 2*(S2-Y1), V = X1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = (Z1+H)^2-Z1Z1-HH + // + // This results in a cost of 7 field multiplications, 4 field squarings, + // 9 field additions, and 4 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. Since + // any number of Jacobian coordinates can represent the same affine + // point, the x and y values need to be converted to like terms. Due to + // the assumption made for this function that the second point has a z + // value of 1 (z2=1), the first point is already "converted". + var z1z1, u2, s2 FieldVal + z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1) + u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1) + s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1) + if x1.Equals(&u2) { + if y1.Equals(&s2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, hh, i, j, r, rr, v FieldVal + var negX1, negY1, negX3 FieldVal + negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2) + h.Add2(&u2, &negX1) // H = U2-X1 (mag: 3) + hh.SquareVal(&h) // HH = H^2 (mag: 1) + i.Set(&hh).MulInt(4) // I = 4 * HH (mag: 4) + j.Mul2(&h, &i) // J = H*I (mag: 1) + negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2) + r.Set(&s2).Add(&negY1).MulInt(2) // r = 2*(S2-Y1) (mag: 6) + rr.SquareVal(&r) // rr = r^2 (mag: 1) + v.Mul2(x1, &i) // V = X1*I (mag: 1) + x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4) + x3.Add(&rr) // X3 = r^2+X3 (mag: 5) + negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6) + y3.Set(y1).Mul(&j).MulInt(2).Negate(2) // Y3 = -(2*Y1*J) (mag: 3) + y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4) + z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1) + z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addGeneric adds two Jacobian points without any assumptions about the z +// values of the two points and stores the result in the provided result param. +// That is to say result = p1 + p2. It is the slowest of the add routines due +// to requiring the most arithmetic. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addGeneric(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + // + // In particular it performs the calculations using the following: + // Z1Z1 = Z1^2, Z2Z2 = Z2^2, U1 = X1*Z2Z2, U2 = X2*Z1Z1, S1 = Y1*Z2*Z2Z2 + // S2 = Y2*Z1*Z1Z1, H = U2-U1, I = (2*H)^2, J = H*I, r = 2*(S2-S1) + // V = U1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*S1*J, Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H + // + // This results in a cost of 11 field multiplications, 5 field squarings, + // 9 field additions, and 4 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2, z2 := &p2.X, &p2.Y, &p2.Z + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity. Since any number of Jacobian coordinates can represent the + // same affine point, the x and y values need to be converted to like + // terms. + var z1z1, z2z2, u1, u2, s1, s2 FieldVal + z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1) + z2z2.SquareVal(z2) // Z2Z2 = Z2^2 (mag: 1) + u1.Set(x1).Mul(&z2z2).Normalize() // U1 = X1*Z2Z2 (mag: 1) + u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1) + s1.Set(y1).Mul(&z2z2).Mul(z2).Normalize() // S1 = Y1*Z2*Z2Z2 (mag: 1) + s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1) + if u1.Equals(&u2) { + if s1.Equals(&s2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, i, j, r, rr, v FieldVal + var negU1, negS1, negX3 FieldVal + negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2) + h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3) + i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 1) + j.Mul2(&h, &i) // J = H*I (mag: 1) + negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2) + r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6) + rr.SquareVal(&r) // rr = r^2 (mag: 1) + v.Mul2(&u1, &i) // V = U1*I (mag: 1) + x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4) + x3.Add(&rr) // X3 = r^2+X3 (mag: 5) + negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6) + y3.Mul2(&s1, &j).MulInt(2).Negate(2) // Y3 = -(2*S1*J) (mag: 3) + y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4) + z3.Add2(z1, z2).Square() // Z3 = (Z1+Z2)^2 (mag: 1) + z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4) + z3.Mul(&h) // Z3 = Z3*H (mag: 1) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// AddNonConst adds the passed Jacobian points together and stores the result in +// the provided result param in *non-constant* time. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func AddNonConst(p1, p2, result *JacobianPoint) { + // The point at infinity is the identity according to the group law for + // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. + if (p1.X.IsZero() && p1.Y.IsZero()) || p1.Z.IsZero() { + result.Set(p2) + return + } + if (p2.X.IsZero() && p2.Y.IsZero()) || p2.Z.IsZero() { + result.Set(p1) + return + } + + // Faster point addition can be achieved when certain assumptions are + // met. For example, when both points have the same z value, arithmetic + // on the z values can be avoided. This section thus checks for these + // conditions and calls an appropriate add function which is accelerated + // by using those assumptions. + isZ1One := p1.Z.IsOne() + isZ2One := p2.Z.IsOne() + switch { + case isZ1One && isZ2One: + addZ1AndZ2EqualsOne(p1, p2, result) + return + case p1.Z.Equals(&p2.Z): + addZ1EqualsZ2(p1, p2, result) + return + case isZ2One: + addZ2EqualsOne(p1, p2, result) + return + } + + // None of the above assumptions are true, so fall back to generic + // point addition. + addGeneric(p1, p2, result) +} + +// doubleZ1EqualsOne performs point doubling on the passed Jacobian point when +// the point is already known to have a z value of 1 and stores the result in +// the provided result param. That is to say result = 2*p. It performs faster +// point doubling than the generic routine since less arithmetic is needed due +// to the ability to avoid multiplication by the z value. +// +// NOTE: The resulting point will be normalized. +func doubleZ1EqualsOne(p, result *JacobianPoint) { + // This function uses the assumptions that z1 is 1, thus the point + // doubling formulas reduce to: + // + // X3 = (3*X1^2)^2 - 8*X1*Y1^2 + // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4 + // Z3 = 2*Y1 + // + // To compute the above efficiently, this implementation splits the + // equation into intermediate elements which are used to minimize the + // number of field multiplications in favor of field squarings which + // are roughly 35% faster than field multiplications with the current + // implementation at the time this was written. + // + // This uses a slightly modified version of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl + // + // In particular it performs the calculations using the following: + // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C) + // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C + // Z3 = 2*Y1 + // + // This results in a cost of 1 field multiplication, 5 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1 := &p.X, &p.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + var a, b, c, d, e, f FieldVal + z3.Set(y1).MulInt(2) // Z3 = 2*Y1 (mag: 2) + a.SquareVal(x1) // A = X1^2 (mag: 1) + b.SquareVal(y1) // B = Y1^2 (mag: 1) + c.SquareVal(&b) // C = B^2 (mag: 1) + b.Add(x1).Square() // B = (X1+B)^2 (mag: 1) + d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3) + d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8) + e.Set(&a).MulInt(3) // E = 3*A (mag: 3) + f.SquareVal(&e) // F = E^2 (mag: 1) + x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17) + x3.Add(&f) // X3 = F+X3 (mag: 18) + f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1) + y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) + y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// doubleGeneric performs point doubling on the passed Jacobian point without +// any assumptions about the z value and stores the result in the provided +// result param. That is to say result = 2*p. It is the slowest of the point +// doubling routines due to requiring the most arithmetic. +// +// NOTE: The resulting point will be normalized. +func doubleGeneric(p, result *JacobianPoint) { + // Point doubling formula for Jacobian coordinates for the secp256k1 + // curve: + // + // X3 = (3*X1^2)^2 - 8*X1*Y1^2 + // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4 + // Z3 = 2*Y1*Z1 + // + // To compute the above efficiently, this implementation splits the + // equation into intermediate elements which are used to minimize the + // number of field multiplications in favor of field squarings which + // are roughly 35% faster than field multiplications with the current + // implementation at the time this was written. + // + // This uses a slightly modified version of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + // + // In particular it performs the calculations using the following: + // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C) + // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C + // Z3 = 2*Y1*Z1 + // + // This results in a cost of 1 field multiplication, 5 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1, z1 := &p.X, &p.Y, &p.Z + x3, y3, z3 := &result.X, &result.Y, &result.Z + var a, b, c, d, e, f FieldVal + z3.Mul2(y1, z1).MulInt(2) // Z3 = 2*Y1*Z1 (mag: 2) + a.SquareVal(x1) // A = X1^2 (mag: 1) + b.SquareVal(y1) // B = Y1^2 (mag: 1) + c.SquareVal(&b) // C = B^2 (mag: 1) + b.Add(x1).Square() // B = (X1+B)^2 (mag: 1) + d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3) + d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8) + e.Set(&a).MulInt(3) // E = 3*A (mag: 3) + f.SquareVal(&e) // F = E^2 (mag: 1) + x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17) + x3.Add(&f) // X3 = F+X3 (mag: 18) + f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1) + y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) + y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) + + // Normalize the resulting field values as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// DoubleNonConst doubles the passed Jacobian point and stores the result in the +// provided result parameter in *non-constant* time. +// +// NOTE: The point must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func DoubleNonConst(p, result *JacobianPoint) { + // Doubling the point at infinity is still infinity. + if p.Y.IsZero() || p.Z.IsZero() { + result.X.SetInt(0) + result.Y.SetInt(0) + result.Z.SetInt(0) + return + } + + // Slightly faster point doubling can be achieved when the z value is 1 + // by avoiding the multiplication on the z value. This section calls + // a point doubling function which is accelerated by using that + // assumption when possible. + if p.Z.IsOne() { + doubleZ1EqualsOne(p, result) + return + } + + // Fall back to generic point doubling which works with arbitrary z + // values. + doubleGeneric(p, result) +} + +// mulAdd64 multiplies the two passed base 2^64 digits together, adds the given +// value to the result, and returns the 128-bit result via a (hi, lo) tuple +// where the upper half of the bits are returned in hi and the lower half in lo. +func mulAdd64(digit1, digit2, m uint64) (hi, lo uint64) { + // Note the carry on the final add is safe to discard because the maximum + // possible value is: + // (2^64 - 1)(2^64 - 1) + (2^64 - 1) = 2^128 - 2^64 + // and: + // 2^128 - 2^64 < 2^128. + var c uint64 + hi, lo = bits.Mul64(digit1, digit2) + lo, c = bits.Add64(lo, m, 0) + hi, _ = bits.Add64(hi, 0, c) + return hi, lo +} + +// mulAdd64Carry multiplies the two passed base 2^64 digits together, adds both +// the given value and carry to the result, and returns the 128-bit result via a +// (hi, lo) tuple where the upper half of the bits are returned in hi and the +// lower half in lo. +func mulAdd64Carry(digit1, digit2, m, c uint64) (hi, lo uint64) { + // Note the carry on the high order add is safe to discard because the + // maximum possible value is: + // (2^64 - 1)(2^64 - 1) + 2*(2^64 - 1) = 2^128 - 1 + // and: + // 2^128 - 1 < 2^128. + var c2 uint64 + hi, lo = mulAdd64(digit1, digit2, m) + lo, c2 = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, c2) + return hi, lo +} + +// mul512Rsh320Round computes the full 512-bit product of the two given scalars, +// right shifts the result by 320 bits, rounds to the nearest integer, and +// returns the result in constant time. +// +// Note that despite the inputs and output being mod n scalars, the 512-bit +// product is NOT reduced mod N prior to the right shift. This is intentional +// because it is used for replacing division with multiplication and thus the +// intermediate results must be done via a field extension to a larger field. +func mul512Rsh320Round(n1, n2 *ModNScalar) ModNScalar { + // Convert n1 and n2 to base 2^64 digits. + n1Digit0 := uint64(n1.n[0]) | uint64(n1.n[1])<<32 + n1Digit1 := uint64(n1.n[2]) | uint64(n1.n[3])<<32 + n1Digit2 := uint64(n1.n[4]) | uint64(n1.n[5])<<32 + n1Digit3 := uint64(n1.n[6]) | uint64(n1.n[7])<<32 + n2Digit0 := uint64(n2.n[0]) | uint64(n2.n[1])<<32 + n2Digit1 := uint64(n2.n[2]) | uint64(n2.n[3])<<32 + n2Digit2 := uint64(n2.n[4]) | uint64(n2.n[5])<<32 + n2Digit3 := uint64(n2.n[6]) | uint64(n2.n[7])<<32 + + // Compute the full 512-bit product n1*n2. + var r0, r1, r2, r3, r4, r5, r6, r7, c uint64 + + // Terms resulting from the product of the first digit of the second number + // by all digits of the first number. + // + // Note that r0 is ignored because it is not needed to compute the higher + // terms and it is shifted out below anyway. + c, _ = bits.Mul64(n2Digit0, n1Digit0) + c, r1 = mulAdd64(n2Digit0, n1Digit1, c) + c, r2 = mulAdd64(n2Digit0, n1Digit2, c) + r4, r3 = mulAdd64(n2Digit0, n1Digit3, c) + + // Terms resulting from the product of the second digit of the second number + // by all digits of the first number. + // + // Note that r1 is ignored because it is no longer needed to compute the + // higher terms and it is shifted out below anyway. + c, _ = mulAdd64(n2Digit1, n1Digit0, r1) + c, r2 = mulAdd64Carry(n2Digit1, n1Digit1, r2, c) + c, r3 = mulAdd64Carry(n2Digit1, n1Digit2, r3, c) + r5, r4 = mulAdd64Carry(n2Digit1, n1Digit3, r4, c) + + // Terms resulting from the product of the third digit of the second number + // by all digits of the first number. + // + // Note that r2 is ignored because it is no longer needed to compute the + // higher terms and it is shifted out below anyway. + c, _ = mulAdd64(n2Digit2, n1Digit0, r2) + c, r3 = mulAdd64Carry(n2Digit2, n1Digit1, r3, c) + c, r4 = mulAdd64Carry(n2Digit2, n1Digit2, r4, c) + r6, r5 = mulAdd64Carry(n2Digit2, n1Digit3, r5, c) + + // Terms resulting from the product of the fourth digit of the second number + // by all digits of the first number. + // + // Note that r3 is ignored because it is no longer needed to compute the + // higher terms and it is shifted out below anyway. + c, _ = mulAdd64(n2Digit3, n1Digit0, r3) + c, r4 = mulAdd64Carry(n2Digit3, n1Digit1, r4, c) + c, r5 = mulAdd64Carry(n2Digit3, n1Digit2, r5, c) + r7, r6 = mulAdd64Carry(n2Digit3, n1Digit3, r6, c) + + // At this point the upper 256 bits of the full 512-bit product n1*n2 are in + // r4..r7 (recall the low order results were discarded as noted above). + // + // Right shift the result 320 bits. Note that the MSB of r4 determines + // whether or not to round because it is the final bit that is shifted out. + // + // Also, notice that r3..r7 would also ordinarily be set to 0 as well for + // the full shift, but that is skipped since they are no longer used as + // their values are known to be zero. + roundBit := r4 >> 63 + r2, r1, r0 = r7, r6, r5 + + // Conditionally add 1 depending on the round bit in constant time. + r0, c = bits.Add64(r0, roundBit, 0) + r1, c = bits.Add64(r1, 0, c) + r2, r3 = bits.Add64(r2, 0, c) + + // Finally, convert the result to a mod n scalar. + // + // No modular reduction is needed because the result is guaranteed to be + // less than the group order given the group order is > 2^255 and the + // maximum possible value of the result is 2^192. + var result ModNScalar + result.n[0] = uint32(r0) + result.n[1] = uint32(r0 >> 32) + result.n[2] = uint32(r1) + result.n[3] = uint32(r1 >> 32) + result.n[4] = uint32(r2) + result.n[5] = uint32(r2 >> 32) + result.n[6] = uint32(r3) + result.n[7] = uint32(r3 >> 32) + return result +} + +// splitK returns two scalars (k1 and k2) that are a balanced length-two +// representation of the provided scalar such that k ≡ k1 + k2*λ (mod N), where +// N is the secp256k1 group order. +func splitK(k *ModNScalar) (ModNScalar, ModNScalar) { + // The ultimate goal is to decompose k into two scalars that are around + // half the bit length of k such that the following equation is satisfied: + // + // k1 + k2*λ ≡ k (mod n) + // + // The strategy used here is based on algorithm 3.74 from [GECC] with a few + // modifications to make use of the more efficient mod n scalar type, avoid + // some costly long divisions, and minimize the number of calculations. + // + // Start by defining a function that takes a vector v = ∈ ℤ⨯ℤ: + // + // f(v) = a + bλ (mod n) + // + // Then, find two vectors, v1 = , and v2 = in ℤ⨯ℤ such that: + // 1) v1 and v2 are linearly independent + // 2) f(v1) = f(v2) = 0 + // 3) v1 and v2 have small Euclidean norm + // + // The vectors that satisfy these properties are found via the Euclidean + // algorithm and are precomputed since both n and λ are fixed values for the + // secp256k1 curve. See genprecomps.go for derivation details. + // + // Next, consider k as a vector in ℚ⨯ℚ and by linear algebra write: + // + // = g1*v1 + g2*v2, where g1, g2 ∈ ℚ + // + // Note that, per above, the components of vector v1 are a1 and b1 while the + // components of vector v2 are a2 and b2. Given the vectors v1 and v2 were + // generated such that a1*b2 - a2*b1 = n, solving the equation for g1 and g2 + // yields: + // + // g1 = b2*k / n + // g2 = -b1*k / n + // + // Observe: + // = g1*v1 + g2*v2 + // = (b2*k/n)* + (-b1*k/n)* | substitute + // = + <-a2*b1*k/n, -b2*b1*k/n> | scalar mul + // = | vector add + // = <[a1*b2*k - a2*b1*k]/n, 0> | simplify + // = | factor out k + // = | substitute + // = | simplify + // + // Now, consider an integer-valued vector v: + // + // v = c1*v1 + c2*v2, where c1, c2 ∈ ℤ (mod n) + // + // Since vectors v1 and v2 are linearly independent and were generated such + // that f(v1) = f(v2) = 0, all possible scalars c1 and c2 also produce a + // vector v such that f(v) = 0. + // + // In other words, c1 and c2 can be any integers and the resulting + // decomposition will still satisfy the required equation. However, since + // the goal is to produce a balanced decomposition that provides a + // performance advantage by minimizing max(k1, k2), c1 and c2 need to be + // integers close to g1 and g2, respectively, so the resulting vector v is + // an integer-valued vector that is close to . + // + // Finally, consider the vector u: + // + // u = - v + // + // It follows that f(u) = k and thus the two components of vector u satisfy + // the required equation: + // + // k1 + k2*λ ≡ k (mod n) + // + // Choosing c1 and c2: + // ------------------- + // + // As mentioned above, c1 and c2 need to be integers close to g1 and g2, + // respectively. The algorithm in [GECC] chooses the following values: + // + // c1 = round(g1) = round(b2*k / n) + // c2 = round(g2) = round(-b1*k / n) + // + // However, as section 3.4.2 of [STWS] notes, the aforementioned approach + // requires costly long divisions that can be avoided by precomputing + // rounded estimates as follows: + // + // t = bitlen(n) + 1 + // z1 = round(2^t * b2 / n) + // z2 = round(2^t * -b1 / n) + // + // Then, use those precomputed estimates to perform a multiplication by k + // along with a floored division by 2^t, which is a simple right shift by t: + // + // c1 = floor(k * z1 / 2^t) = (k * z1) >> t + // c2 = floor(k * z2 / 2^t) = (k * z2) >> t + // + // Finally, round up if last bit discarded in the right shift by t is set by + // adding 1. + // + // As a further optimization, rather than setting t = bitlen(n) + 1 = 257 as + // stated by [STWS], this implementation uses a higher precision estimate of + // t = bitlen(n) + 64 = 320 because it allows simplification of the shifts + // in the internal calculations that are done via uint64s and also allows + // the use of floor in the precomputations. + // + // Thus, the calculations this implementation uses are: + // + // z1 = floor(b2<<320 / n) | precomputed + // z2 = floor((-b1)<<320) / n) | precomputed + // c1 = ((k * z1) >> 320) + (((k * z1) >> 319) & 1) + // c2 = ((k * z2) >> 320) + (((k * z2) >> 319) & 1) + // + // Putting it all together: + // ------------------------ + // + // Calculate the following vectors using the values discussed above: + // + // v = c1*v1 + c2*v2 + // u = - v + // + // The two components of the resulting vector v are: + // va = c1*a1 + c2*a2 + // vb = c1*b1 + c2*b2 + // + // Thus, the two components of the resulting vector u are: + // k1 = k - va + // k2 = 0 - vb = -vb + // + // As some final optimizations: + // + // 1) Note that k1 + k2*λ ≡ k (mod n) means that k1 ≡ k - k2*λ (mod n). + // Therefore, the computation of va can be avoided to save two + // field multiplications and a field addition. + // + // 2) Since k1 ≡ k - k2*λ ≡ k + k2*(-λ), an additional field negation is + // saved by storing and using the negative version of λ. + // + // 3) Since k2 ≡ -vb ≡ -(c1*b1 + c2*b2) ≡ c1*(-b1) + c2*(-b2), one more + // field negation is saved by storing and using the negative versions of + // b1 and b2. + // + // k2 = c1*(-b1) + c2*(-b2) + // k1 = k + k2*(-λ) + var k1, k2 ModNScalar + c1 := mul512Rsh320Round(k, endoZ1) + c2 := mul512Rsh320Round(k, endoZ2) + k2.Add2(c1.Mul(endoNegB1), c2.Mul(endoNegB2)) + k1.Mul2(&k2, endoNegLambda).Add(k) + return k1, k2 +} + +// nafScalar represents a positive integer up to a maximum value of 2^256 - 1 +// encoded in non-adjacent form. +// +// NAF is a signed-digit representation where each digit can be +1, 0, or -1. +// +// In order to efficiently encode that information, this type uses two arrays, a +// "positive" array where set bits represent the +1 signed digits and a +// "negative" array where set bits represent the -1 signed digits. 0 is +// represented by neither array having a bit set in that position. +// +// The Pos and Neg methods return the aforementioned positive and negative +// arrays, respectively. +type nafScalar struct { + // pos houses the positive portion of the representation. An additional + // byte is required for the positive portion because the NAF encoding can be + // up to 1 bit longer than the normal binary encoding of the value. + // + // neg houses the negative portion of the representation. Even though the + // additional byte is not required for the negative portion, since it can + // never exceed the length of the normal binary encoding of the value, + // keeping the same length for positive and negative portions simplifies + // working with the representation and allows extra conditional branches to + // be avoided. + // + // start and end specify the starting and ending index to use within the pos + // and neg arrays, respectively. This allows fixed size arrays to be used + // versus needing to dynamically allocate space on the heap. + // + // NOTE: The fields are defined in the order that they are to minimize the + // padding on 32-bit and 64-bit platforms. + pos [33]byte + start, end uint8 + neg [33]byte +} + +// Pos returns the bytes of the encoded value with bits set in the positions +// that represent a signed digit of +1. +func (s *nafScalar) Pos() []byte { + return s.pos[s.start:s.end] +} + +// Neg returns the bytes of the encoded value with bits set in the positions +// that represent a signed digit of -1. +func (s *nafScalar) Neg() []byte { + return s.neg[s.start:s.end] +} + +// naf takes a positive integer up to a maximum value of 2^256 - 1 and returns +// its non-adjacent form (NAF), which is a unique signed-digit representation +// such that no two consecutive digits are nonzero. See the documentation for +// the returned type for details on how the representation is encoded +// efficiently and how to interpret it +// +// NAF is useful in that it has the fewest nonzero digits of any signed digit +// representation, only 1/3rd of its digits are nonzero on average, and at least +// half of the digits will be 0. +// +// The aforementioned properties are particularly beneficial for optimizing +// elliptic curve point multiplication because they effectively minimize the +// number of required point additions in exchange for needing to perform a mix +// of fewer point additions and subtractions and possibly one additional point +// doubling. This is an excellent tradeoff because subtraction of points has +// the same computational complexity as addition of points and point doubling is +// faster than both. +func naf(k []byte) nafScalar { + // Strip leading zero bytes. + for len(k) > 0 && k[0] == 0x00 { + k = k[1:] + } + + // The non-adjacent form (NAF) of a positive integer k is an expression + // k = ∑_(i=0, l-1) k_i * 2^i where k_i ∈ {0,±1}, k_(l-1) != 0, and no two + // consecutive digits k_i are nonzero. + // + // The traditional method of computing the NAF of a positive integer is + // given by algorithm 3.30 in [GECC]. It consists of repeatedly dividing k + // by 2 and choosing the remainder so that the quotient (k−r)/2 is even + // which ensures the next NAF digit is 0. This requires log_2(k) steps. + // + // However, in [BRID], Prodinger notes that a closed form expression for the + // NAF representation is the bitwise difference 3k/2 - k/2. This is more + // efficient as it can be computed in O(1) versus the O(log(n)) of the + // traditional approach. + // + // The following code makes use of that formula to compute the NAF more + // efficiently. + // + // To understand the logic here, observe that the only way the NAF has a + // nonzero digit at a given bit is when either 3k/2 or k/2 has a bit set in + // that position, but not both. In other words, the result of a bitwise + // xor. This can be seen simply by considering that when the bits are the + // same, the subtraction is either 0-0 or 1-1, both of which are 0. + // + // Further, observe that the "+1" digits in the result are contributed by + // 3k/2 while the "-1" digits are from k/2. So, they can be determined by + // taking the bitwise and of each respective value with the result of the + // xor which identifies which bits are nonzero. + // + // Using that information, this loops backwards from the least significant + // byte to the most significant byte while performing the aforementioned + // calculations by propagating the potential carry and high order bit from + // the next word during the right shift. + kLen := len(k) + var result nafScalar + var carry uint8 + for byteNum := kLen - 1; byteNum >= 0; byteNum-- { + // Calculate k/2. Notice the carry from the previous word is added and + // the low order bit from the next word is shifted in accordingly. + kc := uint16(k[byteNum]) + uint16(carry) + var nextWord uint8 + if byteNum > 0 { + nextWord = k[byteNum-1] + } + halfK := kc>>1 | uint16(nextWord<<7) + + // Calculate 3k/2 and determine the non-zero digits in the result. + threeHalfK := kc + halfK + nonZeroResultDigits := threeHalfK ^ halfK + + // Determine the signed digits {0, ±1}. + result.pos[byteNum+1] = uint8(threeHalfK & nonZeroResultDigits) + result.neg[byteNum+1] = uint8(halfK & nonZeroResultDigits) + + // Propagate the potential carry from the 3k/2 calculation. + carry = uint8(threeHalfK >> 8) + } + result.pos[0] = carry + + // Set the starting and ending positions within the fixed size arrays to + // identify the bytes that are actually used. This is important since the + // encoding is big endian and thus trailing zero bytes changes its value. + result.start = 1 - carry + result.end = uint8(kLen + 1) + return result +} + +// ScalarMultNonConst multiplies k*P where k is a scalar modulo the curve order +// and P is a point in Jacobian projective coordinates and stores the result in +// the provided Jacobian point. +// +// NOTE: The point must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { + // ------------------------------------------------------------------------- + // This makes use of the following efficiently-computable endomorphism to + // accelerate the computation: + // + // φ(P) ⟼ λ*P = (β*P.x mod p, P.y) + // + // In other words, there is a special scalar λ that every point on the + // elliptic curve can be multiplied by that will result in the same point as + // performing a single field multiplication of the point's X coordinate by + // the special value β. + // + // This is useful because scalar point multiplication is significantly more + // expensive than a single field multiplication given the former involves a + // series of point doublings and additions which themselves consist of a + // combination of several field multiplications, squarings, and additions. + // + // So, the idea behind making use of the endomorphism is thus to decompose + // the scalar into two scalars that are each about half the bit length of + // the original scalar such that: + // + // k ≡ k1 + k2*λ (mod n) + // + // This in turn allows the scalar point multiplication to be performed as a + // sum of two smaller half-length multiplications as follows: + // + // k*P = (k1 + k2*λ)*P + // = k1*P + k2*λ*P + // = k1*P + k2*φ(P) + // + // Thus, a speedup is achieved so long as it's faster to decompose the + // scalar, compute φ(P), and perform a simultaneous multiply of the + // half-length point multiplications than it is to compute a full width + // point multiplication. + // + // In practice, benchmarks show the current implementation provides a + // speedup of around 30-35% versus not using the endomorphism. + // + // See section 3.5 in [GECC] for a more rigorous treatment. + // ------------------------------------------------------------------------- + + // Per above, the main equation here to remember is: + // k*P = k1*P + k2*φ(P) + // + // p1 below is P in the equation while p2 is φ(P) in the equation. + // + // NOTE: φ(x,y) = (β*x,y). The Jacobian z coordinates are the same, so this + // math goes through. + // + // Also, calculate -p1 and -p2 for use in the NAF optimization. + p1, p1Neg := new(JacobianPoint), new(JacobianPoint) + p1.Set(point) + p1Neg.Set(p1) + p1Neg.Y.Negate(1).Normalize() + p2, p2Neg := new(JacobianPoint), new(JacobianPoint) + p2.Set(p1) + p2.X.Mul(endoBeta).Normalize() + p2Neg.Set(p2) + p2Neg.Y.Negate(1).Normalize() + + // Decompose k into k1 and k2 such that k = k1 + k2*λ (mod n) where k1 and + // k2 are around half the bit length of k in order to halve the number of EC + // operations. + // + // Notice that this also flips the sign of the scalars and points as needed + // to minimize the bit lengths of the scalars k1 and k2. + // + // This is done because the scalars are operating modulo the group order + // which means that when they would otherwise be a small negative magnitude + // they will instead be a large positive magnitude. Since the goal is for + // the scalars to have a small magnitude to achieve a performance boost, use + // their negation when they are greater than the half order of the group and + // flip the positive and negative values of the corresponding point that + // will be multiplied by to compensate. + // + // In other words, transform the calc when k1 is over the half order to: + // k1*P = -k1*-P + // + // Similarly, transform the calc when k2 is over the half order to: + // k2*φ(P) = -k2*-φ(P) + k1, k2 := splitK(k) + if k1.IsOverHalfOrder() { + k1.Negate() + p1, p1Neg = p1Neg, p1 + } + if k2.IsOverHalfOrder() { + k2.Negate() + p2, p2Neg = p2Neg, p2 + } + + // Convert k1 and k2 into their NAF representations since NAF has a lot more + // zeros overall on average which minimizes the number of required point + // additions in exchange for a mix of fewer point additions and subtractions + // at the cost of one additional point doubling. + // + // This is an excellent tradeoff because subtraction of points has the same + // computational complexity as addition of points and point doubling is + // faster than both. + // + // Concretely, on average, 1/2 of all bits will be non-zero with the normal + // binary representation whereas only 1/3rd of the bits will be non-zero + // with NAF. + // + // The Pos version of the bytes contain the +1s and the Neg versions contain + // the -1s. + k1Bytes, k2Bytes := k1.Bytes(), k2.Bytes() + k1NAF, k2NAF := naf(k1Bytes[:]), naf(k2Bytes[:]) + k1PosNAF, k1NegNAF := k1NAF.Pos(), k1NAF.Neg() + k2PosNAF, k2NegNAF := k2NAF.Pos(), k2NAF.Neg() + k1Len, k2Len := len(k1PosNAF), len(k2PosNAF) + + // Add left-to-right using the NAF optimization. See algorithm 3.77 from + // [GECC]. + // + // Point Q = ∞ (point at infinity). + var q JacobianPoint + m := k1Len + if m < k2Len { + m = k2Len + } + for i := 0; i < m; i++ { + // Since k1 and k2 are potentially different lengths and the calculation + // is being done left to right, pad the front of the shorter one with + // 0s. + var k1BytePos, k1ByteNeg, k2BytePos, k2ByteNeg byte + if i >= m-k1Len { + k1BytePos, k1ByteNeg = k1PosNAF[i-(m-k1Len)], k1NegNAF[i-(m-k1Len)] + } + if i >= m-k2Len { + k2BytePos, k2ByteNeg = k2PosNAF[i-(m-k2Len)], k2NegNAF[i-(m-k2Len)] + } + + for mask := uint8(1 << 7); mask > 0; mask >>= 1 { + // Q = 2 * Q + DoubleNonConst(&q, &q) + + // Add or subtract the first point based on the signed digit of the + // NAF representation of k1 at this bit position. + // + // +1: Q = Q + p1 + // -1: Q = Q - p1 + // 0: Q = Q (no change) + if k1BytePos&mask == mask { + AddNonConst(&q, p1, &q) + } else if k1ByteNeg&mask == mask { + AddNonConst(&q, p1Neg, &q) + } + + // Add or subtract the second point based on the signed digit of the + // NAF representation of k2 at this bit position. + // + // +1: Q = Q + p2 + // -1: Q = Q - p2 + // 0: Q = Q (no change) + if k2BytePos&mask == mask { + AddNonConst(&q, p2, &q) + } else if k2ByteNeg&mask == mask { + AddNonConst(&q, p2Neg, &q) + } + } + } + + result.Set(&q) +} + +// ScalarBaseMultNonConst multiplies k*G where k is a scalar modulo the curve +// order and G is the base point of the group and stores the result in the +// provided Jacobian point. +// +// NOTE: The resulting point will be normalized. +func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + scalarBaseMultNonConst(k, result) +} + +// jacobianG is the secp256k1 base point converted to Jacobian coordinates and +// is defined here to avoid repeatedly converting it. +var jacobianG = func() JacobianPoint { + var G JacobianPoint + bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &G) + return G +}() + +// scalarBaseMultNonConstSlow computes k*G through ScalarMultNonConst. +func scalarBaseMultNonConstSlow(k *ModNScalar, result *JacobianPoint) { + ScalarMultNonConst(k, &jacobianG, result) +} + +// scalarBaseMultNonConstFast computes k*G through the precomputed lookup +// tables. +func scalarBaseMultNonConstFast(k *ModNScalar, result *JacobianPoint) { + bytePoints := s256BytePoints() + + // Start with the point at infinity. + result.X.Zero() + result.Y.Zero() + result.Z.Zero() + + // bytePoints has all 256 byte points for each 8-bit window. The strategy + // is to add up the byte points. This is best understood by expressing k in + // base-256 which it already sort of is. Each "digit" in the 8-bit window + // can be looked up using bytePoints and added together. + kb := k.Bytes() + for i := 0; i < len(kb); i++ { + pt := &bytePoints[i][kb[i]] + AddNonConst(result, pt, result) + } +} + +// isOnCurve returns whether or not the affine point (x,y) is on the curve. +func isOnCurve(fx, fy *FieldVal) bool { + // Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7 + y2 := new(FieldVal).SquareVal(fy).Normalize() + result := new(FieldVal).SquareVal(fx).Mul(fx).AddInt(7).Normalize() + return y2.Equals(result) +} + +// DecompressY attempts to calculate the Y coordinate for the given X coordinate +// such that the result pair is a point on the secp256k1 curve. It adjusts Y +// based on the desired oddness and returns whether or not it was successful +// since not all X coordinates are valid. +// +// The magnitude of the provided X coordinate field value must be a max of 8 for +// a correct result. The resulting Y field value will have a magnitude of 1. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: Yes if the func returns true, no otherwise +// Output Max Magnitude: 1 +func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool { + // The curve equation for secp256k1 is: y^2 = x^3 + 7. Thus + // y = +-sqrt(x^3 + 7). + // + // The x coordinate must be invalid if there is no square root for the + // calculated rhs because it means the X coordinate is not for a point on + // the curve. + x3PlusB := new(FieldVal).SquareVal(x).Mul(x).AddInt(7) + if hasSqrt := resultY.SquareRootVal(x3PlusB); !hasSqrt { + return false + } + if resultY.Normalize().IsOdd() != odd { + resultY.Negate(1).Normalize() + } + return true +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go new file mode 100644 index 0000000000..16288318c1 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_embedded.go @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +//go:build tinygo + +package secp256k1 + +// This file contains the variants suitable for +// memory or storage constrained environments. + +func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + scalarBaseMultNonConstSlow(k, result) +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go new file mode 100644 index 0000000000..cf84f770ed --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/curve_precompute.go @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +//go:build !tinygo + +package secp256k1 + +// This file contains the variants that don't fit in +// memory or storage constrained environments. + +func scalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + scalarBaseMultNonConstFast(k, result) +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go new file mode 100644 index 0000000000..ac01e2343c --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/doc.go @@ -0,0 +1,59 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package secp256k1 implements optimized secp256k1 elliptic curve operations in +pure Go. + +This package provides an optimized pure Go implementation of elliptic curve +cryptography operations over the secp256k1 curve as well as data structures and +functions for working with public and private secp256k1 keys. See +https://www.secg.org/sec2-v2.pdf for details on the standard. + +In addition, sub packages are provided to produce, verify, parse, and serialize +ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme +specific to Decred) signatures. See the README.md files in the relevant sub +packages for more details about those aspects. + +An overview of the features provided by this package are as follows: + + - Private key generation, serialization, and parsing + - Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys + - Specialized types for performing optimized and constant time field operations + - FieldVal type for working modulo the secp256k1 field prime + - ModNScalar type for working modulo the secp256k1 group order + - Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) + - Point decompression from a given x coordinate + - Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing + algorithms + +It also provides an implementation of the Go standard library crypto/elliptic +Curve interface via the S256 function so that it may be used with other packages +in the standard library such as crypto/tls, crypto/x509, and crypto/ecdsa. +However, in the case of ECDSA, it is highly recommended to use the ecdsa sub +package of this package instead since it is optimized specifically for secp256k1 +and is significantly faster as a result. + +Although this package was primarily written for dcrd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use optimized secp256k1 elliptic curve cryptography. + +Finally, a comprehensive suite of tests is provided to provide a high level of +quality assurance. + +# Use of secp256k1 in Decred + +At the time of this writing, the primary public key cryptography in widespread +use on the Decred network used to secure coins is based on elliptic curves +defined by the secp256k1 domain parameters. +*/ +package secp256k1 diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go new file mode 100644 index 0000000000..96869a3cd9 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdh.go @@ -0,0 +1,21 @@ +// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2023 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// GenerateSharedSecret generates a shared secret based on a private key and a +// public key using Diffie-Hellman key exchange (ECDH) (RFC 5903). +// RFC5903 Section 9 states we should only return x. +// +// It is recommended to securely hash the result before using as a cryptographic +// key. +func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte { + var point, result JacobianPoint + pubkey.AsJacobian(&point) + ScalarMultNonConst(&privkey.Key, &point, &result) + result.ToAffine() + xBytes := result.X.Bytes() + return xBytes[:] +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go new file mode 100644 index 0000000000..a3a45af317 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/ellipticadaptor.go @@ -0,0 +1,255 @@ +// Copyright 2020-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "math/big" +) + +// CurveParams contains the parameters for the secp256k1 curve. +type CurveParams struct { + // P is the prime used in the secp256k1 field. + P *big.Int + + // N is the order of the secp256k1 curve group generated by the base point. + N *big.Int + + // Gx and Gy are the x and y coordinate of the base point, respectively. + Gx, Gy *big.Int + + // BitSize is the size of the underlying secp256k1 field in bits. + BitSize int + + // H is the cofactor of the secp256k1 curve. + H int + + // ByteSize is simply the bit size / 8 and is provided for convenience + // since it is calculated repeatedly. + ByteSize int +} + +// Curve parameters taken from [SECG] section 2.4.1. +var curveParams = CurveParams{ + P: fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), + N: fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + Gx: fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), + Gy: fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), + BitSize: 256, + H: 1, + ByteSize: 256 / 8, +} + +// Params returns the secp256k1 curve parameters for convenience. +func Params() *CurveParams { + return &curveParams +} + +// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve +// interface from crypto/elliptic. +type KoblitzCurve struct { + *elliptic.CurveParams +} + +// bigAffineToJacobian takes an affine point (x, y) as big integers and converts +// it to Jacobian point with Z=1. +func bigAffineToJacobian(x, y *big.Int, result *JacobianPoint) { + result.X.SetByteSlice(x.Bytes()) + result.Y.SetByteSlice(y.Bytes()) + result.Z.SetInt(1) +} + +// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and +// converts it to an affine point as big integers. +func jacobianToBigAffine(point *JacobianPoint) (*big.Int, *big.Int) { + point.ToAffine() + + // Convert the field values for the now affine point to big.Ints. + x3, y3 := new(big.Int), new(big.Int) + x3.SetBytes(point.X.Bytes()[:]) + y3.SetBytes(point.Y.Bytes()[:]) + return x3, y3 +} + +// Params returns the parameters for the curve. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Params() *elliptic.CurveParams { + return curve.CurveParams +} + +// IsOnCurve returns whether or not the affine point (x,y) is on the curve. +// +// This is part of the elliptic.Curve interface implementation. This function +// differs from the crypto/elliptic algorithm since a = 0 not -3. +func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool { + // Convert big ints to a Jacobian point for faster arithmetic. + var point JacobianPoint + bigAffineToJacobian(x, y, &point) + return isOnCurve(&point.X, &point.Y) +} + +// Add returns the sum of (x1,y1) and (x2,y2). +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + // The point at infinity is the identity according to the group law for + // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. + if x1.Sign() == 0 && y1.Sign() == 0 { + return x2, y2 + } + if x2.Sign() == 0 && y2.Sign() == 0 { + return x1, y1 + } + + // Convert the affine coordinates from big integers to Jacobian points, + // do the point addition in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var p1, p2, result JacobianPoint + bigAffineToJacobian(x1, y1, &p1) + bigAffineToJacobian(x2, y2, &p2) + AddNonConst(&p1, &p2, &result) + return jacobianToBigAffine(&result) +} + +// Double returns 2*(x1,y1). +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + if y1.Sign() == 0 { + return new(big.Int), new(big.Int) + } + + // Convert the affine coordinates from big integers to Jacobian points, + // do the point doubling in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var point, result JacobianPoint + bigAffineToJacobian(x1, y1, &point) + DoubleNonConst(&point, &result) + return jacobianToBigAffine(&result) +} + +// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This +// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and +// thus any other valid point on the elliptic curve has the same order. +func moduloReduce(k []byte) []byte { + // Since the order of G is curve.N, we can use a much smaller number by + // doing modulo curve.N + if len(k) > curveParams.ByteSize { + tmpK := new(big.Int).SetBytes(k) + tmpK.Mod(tmpK, curveParams.N) + return tmpK.Bytes() + } + + return k +} + +// ScalarMult returns k*(bx, by) where k is a big endian integer. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) ScalarMult(bx, by *big.Int, k []byte) (*big.Int, *big.Int) { + // Convert the affine coordinates from big integers to Jacobian points, + // do the multiplication in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var kModN ModNScalar + kModN.SetByteSlice(moduloReduce(k)) + var point, result JacobianPoint + bigAffineToJacobian(bx, by, &point) + ScalarMultNonConst(&kModN, &point, &result) + return jacobianToBigAffine(&result) +} + +// ScalarBaseMult returns k*G where G is the base point of the group and k is a +// big endian integer. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + // Perform the multiplication and convert the Jacobian point back to affine + // big.Ints. + var kModN ModNScalar + kModN.SetByteSlice(moduloReduce(k)) + var result JacobianPoint + ScalarBaseMultNonConst(&kModN, &result) + return jacobianToBigAffine(&result) +} + +// X returns the x coordinate of the public key. +func (p *PublicKey) X() *big.Int { + return new(big.Int).SetBytes(p.x.Bytes()[:]) +} + +// Y returns the y coordinate of the public key. +func (p *PublicKey) Y() *big.Int { + return new(big.Int).SetBytes(p.y.Bytes()[:]) +} + +// ToECDSA returns the public key as a *ecdsa.PublicKey. +func (p *PublicKey) ToECDSA() *ecdsa.PublicKey { + return &ecdsa.PublicKey{ + Curve: S256(), + X: p.X(), + Y: p.Y(), + } +} + +// ToECDSA returns the private key as a *ecdsa.PrivateKey. +func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey { + var privKeyBytes [PrivKeyBytesLen]byte + p.Key.PutBytes(&privKeyBytes) + var result JacobianPoint + ScalarBaseMultNonConst(&p.Key, &result) + x, y := jacobianToBigAffine(&result) + newPrivKey := &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: S256(), + X: x, + Y: y, + }, + D: new(big.Int).SetBytes(privKeyBytes[:]), + } + zeroArray32(&privKeyBytes) + return newPrivKey +} + +// fromHex converts the passed hex string into a big integer pointer and will +// panic is there is an error. This is only provided for the hard-coded +// constants so errors in the source code can bet detected. It will only (and +// must only) be called for initialization purposes. +func fromHex(s string) *big.Int { + if s == "" { + return big.NewInt(0) + } + r, ok := new(big.Int).SetString(s, 16) + if !ok { + panic("invalid hex in source file: " + s) + } + return r +} + +// secp256k1 is a global instance of the KoblitzCurve implementation which in +// turn embeds and implements elliptic.CurveParams. +var secp256k1 = &KoblitzCurve{ + CurveParams: &elliptic.CurveParams{ + P: curveParams.P, + N: curveParams.N, + B: fromHex("0000000000000000000000000000000000000000000000000000000000000007"), + Gx: curveParams.Gx, + Gy: curveParams.Gy, + BitSize: curveParams.BitSize, + Name: "secp256k1", + }, +} + +// S256 returns an elliptic.Curve which implements secp256k1. +func S256() *KoblitzCurve { + return secp256k1 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go new file mode 100644 index 0000000000..ac8c45127e --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/error.go @@ -0,0 +1,67 @@ +// Copyright (c) 2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// ErrorKind identifies a kind of error. It has full support for errors.Is and +// errors.As, so the caller can directly check against an error kind when +// determining the reason for an error. +type ErrorKind string + +// These constants are used to identify a specific RuleError. +const ( + // ErrPubKeyInvalidLen indicates that the length of a serialized public + // key is not one of the allowed lengths. + ErrPubKeyInvalidLen = ErrorKind("ErrPubKeyInvalidLen") + + // ErrPubKeyInvalidFormat indicates an attempt was made to parse a public + // key that does not specify one of the supported formats. + ErrPubKeyInvalidFormat = ErrorKind("ErrPubKeyInvalidFormat") + + // ErrPubKeyXTooBig indicates that the x coordinate for a public key + // is greater than or equal to the prime of the field underlying the group. + ErrPubKeyXTooBig = ErrorKind("ErrPubKeyXTooBig") + + // ErrPubKeyYTooBig indicates that the y coordinate for a public key is + // greater than or equal to the prime of the field underlying the group. + ErrPubKeyYTooBig = ErrorKind("ErrPubKeyYTooBig") + + // ErrPubKeyNotOnCurve indicates that a public key is not a point on the + // secp256k1 curve. + ErrPubKeyNotOnCurve = ErrorKind("ErrPubKeyNotOnCurve") + + // ErrPubKeyMismatchedOddness indicates that a hybrid public key specified + // an oddness of the y coordinate that does not match the actual oddness of + // the provided y coordinate. + ErrPubKeyMismatchedOddness = ErrorKind("ErrPubKeyMismatchedOddness") +) + +// Error satisfies the error interface and prints human-readable errors. +func (e ErrorKind) Error() string { + return string(e) +} + +// Error identifies an error related to public key cryptography using a +// sec256k1 curve. It has full support for errors.Is and errors.As, so the +// caller can ascertain the specific reason for the error by checking +// the underlying error. +type Error struct { + Err error + Description string +} + +// Error satisfies the error interface and prints human-readable errors. +func (e Error) Error() string { + return e.Description +} + +// Unwrap returns the underlying wrapped error. +func (e Error) Unwrap() error { + return e.Err +} + +// makeError creates an Error given a set of arguments. +func makeError(kind ErrorKind, desc string) Error { + return Error{Err: kind, Description: desc} +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go new file mode 100644 index 0000000000..f979bb2efe --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go @@ -0,0 +1,1696 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Copyright (c) 2013-2024 Dave Collins +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone. +// http://cacr.uwaterloo.ca/hac/ + +// All elliptic curve operations for secp256k1 are done in a finite field +// characterized by a 256-bit prime. Given this precision is larger than the +// biggest available native type, obviously some form of bignum math is needed. +// This package implements specialized fixed-precision field arithmetic rather +// than relying on an arbitrary-precision arithmetic package such as math/big +// for dealing with the field math since the size is known. As a result, rather +// large performance gains are achieved by taking advantage of many +// optimizations not available to arbitrary-precision arithmetic and generic +// modular arithmetic algorithms. +// +// There are various ways to internally represent each finite field element. +// For example, the most obvious representation would be to use an array of 4 +// uint64s (64 bits * 4 = 256 bits). However, that representation suffers from +// a couple of issues. First, there is no native Go type large enough to handle +// the intermediate results while adding or multiplying two 64-bit numbers, and +// second there is no space left for overflows when performing the intermediate +// arithmetic between each array element which would lead to expensive carry +// propagation. +// +// Given the above, this implementation represents the field elements as +// 10 uint32s with each word (array entry) treated as base 2^26. This was +// chosen for the following reasons: +// 1) Most systems at the current time are 64-bit (or at least have 64-bit +// registers available for specialized purposes such as MMX) so the +// intermediate results can typically be done using a native register (and +// using uint64s to avoid the need for additional half-word arithmetic) +// 2) In order to allow addition of the internal words without having to +// propagate the carry, the max normalized value for each register must +// be less than the number of bits available in the register +// 3) Since we're dealing with 32-bit values, 64-bits of overflow is a +// reasonable choice for #2 +// 4) Given the need for 256-bits of precision and the properties stated in #1, +// #2, and #3, the representation which best accommodates this is 10 uint32s +// with base 2^26 (26 bits * 10 = 260 bits, so the final word only needs 22 +// bits) which leaves the desired 64 bits (32 * 10 = 320, 320 - 256 = 64) for +// overflow +// +// Since it is so important that the field arithmetic is extremely fast for high +// performance crypto, this type does not perform any validation where it +// ordinarily would. See the documentation for FieldVal for more details. + +import ( + "encoding/hex" +) + +// Constants used to make the code more readable. +const ( + twoBitsMask = 0x3 + fourBitsMask = 0xf + sixBitsMask = 0x3f + eightBitsMask = 0xff +) + +// Constants related to the field representation. +const ( + // fieldWords is the number of words used to internally represent the + // 256-bit value. + fieldWords = 10 + + // fieldBase is the exponent used to form the numeric base of each word. + // 2^(fieldBase*i) where i is the word position. + fieldBase = 26 + + // fieldBaseMask is the mask for the bits in each word needed to + // represent the numeric base of each word (except the most significant + // word). + fieldBaseMask = (1 << fieldBase) - 1 + + // fieldMSBBits is the number of bits in the most significant word used + // to represent the value. + fieldMSBBits = 256 - (fieldBase * (fieldWords - 1)) + + // fieldMSBMask is the mask for the bits in the most significant word + // needed to represent the value. + fieldMSBMask = (1 << fieldMSBBits) - 1 + + // These fields provide convenient access to each of the words of the + // secp256k1 prime in the internal field representation to improve code + // readability. + fieldPrimeWordZero = 0x03fffc2f + fieldPrimeWordOne = 0x03ffffbf + fieldPrimeWordTwo = 0x03ffffff + fieldPrimeWordThree = 0x03ffffff + fieldPrimeWordFour = 0x03ffffff + fieldPrimeWordFive = 0x03ffffff + fieldPrimeWordSix = 0x03ffffff + fieldPrimeWordSeven = 0x03ffffff + fieldPrimeWordEight = 0x03ffffff + fieldPrimeWordNine = 0x003fffff +) + +// FieldVal implements optimized fixed-precision arithmetic over the +// secp256k1 finite field. This means all arithmetic is performed modulo +// +// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. +// +// WARNING: Since it is so important for the field arithmetic to be extremely +// fast for high performance crypto, this type does not perform any validation +// of documented preconditions where it ordinarily would. As a result, it is +// IMPERATIVE for callers to understand some key concepts that are described +// below and ensure the methods are called with the necessary preconditions that +// each method is documented with. For example, some methods only give the +// correct result if the field value is normalized and others require the field +// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS +// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make +// the type more difficult to use correctly and while I typically prefer to +// ensure all state and input is valid for most code, this is a bit of an +// exception because those extra checks really add up in what ends up being +// critical hot paths. +// +// The first key concept when working with this type is normalization. In order +// to avoid the need to propagate a ton of carries, the internal representation +// provides additional overflow bits for each word of the overall 256-bit value. +// This means that there are multiple internal representations for the same +// value and, as a result, any methods that rely on comparison of the value, +// such as equality and oddness determination, require the caller to provide a +// normalized value. +// +// The second key concept when working with this type is magnitude. As +// previously mentioned, the internal representation provides additional +// overflow bits which means that the more math operations that are performed on +// the field value between normalizations, the more those overflow bits +// accumulate. The magnitude is effectively that maximum possible number of +// those overflow bits that could possibly be required as a result of a given +// operation. Since there are only a limited number of overflow bits available, +// this implies that the max possible magnitude MUST be tracked by the caller +// and the caller MUST normalize the field value if a given operation would +// cause the magnitude of the result to exceed the max allowed value. +// +// IMPORTANT: The max allowed magnitude of a field value is 32. +type FieldVal struct { + // Each 256-bit value is represented as 10 32-bit integers in base 2^26. + // This provides 6 bits of overflow in each word (10 bits in the most + // significant word) for a total of 64 bits of overflow (9*6 + 10 = 64). It + // only implements the arithmetic needed for elliptic curve operations. + // + // The following depicts the internal representation: + // ----------------------------------------------------------------- + // | n[9] | n[8] | ... | n[0] | + // | 32 bits available | 32 bits available | ... | 32 bits available | + // | 22 bits for value | 26 bits for value | ... | 26 bits for value | + // | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow | + // | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) | + // ----------------------------------------------------------------- + // + // For example, consider the number 2^49 + 1. It would be represented as: + // n[0] = 1 + // n[1] = 2^23 + // n[2..9] = 0 + // + // The full 256-bit value is then calculated by looping i from 9..0 and + // doing sum(n[i] * 2^(26i)) like so: + // n[9] * 2^(26*9) = 0 * 2^234 = 0 + // n[8] * 2^(26*8) = 0 * 2^208 = 0 + // ... + // n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49 + // n[0] * 2^(26*0) = 1 * 2^0 = 1 + // Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1 + n [10]uint32 +} + +// String returns the field value as a normalized human-readable hex string. +// +// Preconditions: None +// Output Normalized: Field is not modified -- same as input value +// Output Max Magnitude: Field is not modified -- same as input value +func (f FieldVal) String() string { + // f is a copy, so it's safe to normalize it without mutating the original. + f.Normalize() + return hex.EncodeToString(f.Bytes()[:]) +} + +// Zero sets the field value to zero in constant time. A newly created field +// value is already set to zero. This function can be useful to clear an +// existing field value for reuse. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) Zero() { + f.n[0] = 0 + f.n[1] = 0 + f.n[2] = 0 + f.n[3] = 0 + f.n[4] = 0 + f.n[5] = 0 + f.n[6] = 0 + f.n[7] = 0 + f.n[8] = 0 + f.n[9] = 0 +} + +// Set sets the field value equal to the passed value in constant time. The +// normalization and magnitude of the two fields will be identical. +// +// The field value is returned to support chaining. This enables syntax like: +// f := new(FieldVal).Set(f2).Add(1) so that f = f2 + 1 where f2 is not +// modified. +// +// Preconditions: None +// Output Normalized: Same as input value +// Output Max Magnitude: Same as input value +func (f *FieldVal) Set(val *FieldVal) *FieldVal { + *f = *val + return f +} + +// SetInt sets the field value to the passed integer in constant time. This is +// a convenience function since it is fairly common to perform some arithmetic +// with small native integers. +// +// The field value is returned to support chaining. This enables syntax such +// as f := new(FieldVal).SetInt(2).Mul(f2) so that f = 2 * f2. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) SetInt(ui uint16) *FieldVal { + f.Zero() + f.n[0] = uint32(ui) + return f +} + +// SetBytes packs the passed 32-byte big-endian value into the internal field +// value representation in constant time. SetBytes interprets the provided +// array as a 256-bit big-endian unsigned integer, packs it into the internal +// field value representation, and returns either 1 if it is greater than or +// equal to the field prime (aka it overflowed) or 0 otherwise in constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +// +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 +func (f *FieldVal) SetBytes(b *[32]byte) uint32 { + // Pack the 256 total bits across the 10 uint32 words with a max of + // 26-bits per word. This could be done with a couple of for loops, + // but this unrolled version is significantly faster. Benchmarks show + // this is about 34 times faster than the variant which uses loops. + f.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | + (uint32(b[28])&twoBitsMask)<<24 + f.n[1] = uint32(b[28])>>2 | uint32(b[27])<<6 | uint32(b[26])<<14 | + (uint32(b[25])&fourBitsMask)<<22 + f.n[2] = uint32(b[25])>>4 | uint32(b[24])<<4 | uint32(b[23])<<12 | + (uint32(b[22])&sixBitsMask)<<20 + f.n[3] = uint32(b[22])>>6 | uint32(b[21])<<2 | uint32(b[20])<<10 | + uint32(b[19])<<18 + f.n[4] = uint32(b[18]) | uint32(b[17])<<8 | uint32(b[16])<<16 | + (uint32(b[15])&twoBitsMask)<<24 + f.n[5] = uint32(b[15])>>2 | uint32(b[14])<<6 | uint32(b[13])<<14 | + (uint32(b[12])&fourBitsMask)<<22 + f.n[6] = uint32(b[12])>>4 | uint32(b[11])<<4 | uint32(b[10])<<12 | + (uint32(b[9])&sixBitsMask)<<20 + f.n[7] = uint32(b[9])>>6 | uint32(b[8])<<2 | uint32(b[7])<<10 | + uint32(b[6])<<18 + f.n[8] = uint32(b[5]) | uint32(b[4])<<8 | uint32(b[3])<<16 | + (uint32(b[2])&twoBitsMask)<<24 + f.n[9] = uint32(b[2])>>2 | uint32(b[1])<<6 | uint32(b[0])<<14 + + // The intuition here is that the field value is greater than the prime if + // one of the higher individual words is greater than corresponding word of + // the prime and all higher words in the field value are equal to their + // corresponding word of the prime. Since this type is modulo the prime, + // being equal is also an overflow back to 0. + // + // Note that because the input is 32 bytes and it was just packed into the + // field representation, the only words that can possibly be greater are + // zero and one, because ceil(log_2(2^256 - 1 - P)) = 33 bits max and the + // internal field representation encodes 26 bits with each word. + // + // Thus, there is no need to test if the upper words of the field value + // exceeds them, hence, only equality is checked for them. + highWordsEq := constantTimeEq(f.n[9], fieldPrimeWordNine) + highWordsEq &= constantTimeEq(f.n[8], fieldPrimeWordEight) + highWordsEq &= constantTimeEq(f.n[7], fieldPrimeWordSeven) + highWordsEq &= constantTimeEq(f.n[6], fieldPrimeWordSix) + highWordsEq &= constantTimeEq(f.n[5], fieldPrimeWordFive) + highWordsEq &= constantTimeEq(f.n[4], fieldPrimeWordFour) + highWordsEq &= constantTimeEq(f.n[3], fieldPrimeWordThree) + highWordsEq &= constantTimeEq(f.n[2], fieldPrimeWordTwo) + overflow := highWordsEq & constantTimeGreater(f.n[1], fieldPrimeWordOne) + highWordsEq &= constantTimeEq(f.n[1], fieldPrimeWordOne) + overflow |= highWordsEq & constantTimeGreaterOrEq(f.n[0], fieldPrimeWordZero) + + return overflow +} + +// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned +// integer (meaning it is truncated to the first 32 bytes), packs it into the +// internal field value representation, and returns whether or not the resulting +// truncated 256-bit integer is greater than or equal to the field prime (aka it +// overflowed) in constant time. +// +// Note that since passing a slice with more than 32 bytes is truncated, it is +// possible that the truncated value is less than the field prime and hence it +// will not be reported as having overflowed in that case. It is up to the +// caller to decide whether it needs to provide numbers of the appropriate size +// or it if is acceptable to use this function with the described truncation and +// overflow behavior. +// +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 +func (f *FieldVal) SetByteSlice(b []byte) bool { + var b32 [32]byte + b = b[:constantTimeMin(uint32(len(b)), 32)] + copy(b32[:], b32[:32-len(b)]) + copy(b32[32-len(b):], b) + result := f.SetBytes(&b32) + zeroArray32(&b32) + return result != 0 +} + +// Normalize normalizes the internal field words into the desired range and +// performs fast modular reduction over the secp256k1 prime by making use of the +// special form of the prime in constant time. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) Normalize() *FieldVal { + // The field representation leaves 6 bits of overflow in each word so + // intermediate calculations can be performed without needing to + // propagate the carry to each higher word during the calculations. In + // order to normalize, we need to "compact" the full 256-bit value to + // the right while propagating any carries through to the high order + // word. + // + // Since this field is doing arithmetic modulo the secp256k1 prime, we + // also need to perform modular reduction over the prime. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // The algorithm presented in the referenced section typically repeats + // until the quotient is zero. However, due to our field representation + // we already know to within one reduction how many times we would need + // to repeat as it's the uppermost bits of the high order word. Thus we + // can simply multiply the magnitude by the field representation of the + // prime and do a single iteration. After this step there might be an + // additional carry to bit 256 (bit 22 of the high order word). + t9 := f.n[9] + m := t9 >> fieldMSBBits + t9 &= fieldMSBMask + t0 := f.n[0] + m*977 + t1 := (t0 >> fieldBase) + f.n[1] + (m << 6) + t0 &= fieldBaseMask + t2 := (t1 >> fieldBase) + f.n[2] + t1 &= fieldBaseMask + t3 := (t2 >> fieldBase) + f.n[3] + t2 &= fieldBaseMask + t4 := (t3 >> fieldBase) + f.n[4] + t3 &= fieldBaseMask + t5 := (t4 >> fieldBase) + f.n[5] + t4 &= fieldBaseMask + t6 := (t5 >> fieldBase) + f.n[6] + t5 &= fieldBaseMask + t7 := (t6 >> fieldBase) + f.n[7] + t6 &= fieldBaseMask + t8 := (t7 >> fieldBase) + f.n[8] + t7 &= fieldBaseMask + t9 = (t8 >> fieldBase) + t9 + t8 &= fieldBaseMask + + // At this point, the magnitude is guaranteed to be one, however, the + // value could still be greater than the prime if there was either a + // carry through to bit 256 (bit 22 of the higher order word) or the + // value is greater than or equal to the field characteristic. The + // following determines if either or these conditions are true and does + // the final reduction in constant time. + // + // Also note that 'm' will be zero when neither of the aforementioned + // conditions are true and the value will not be changed when 'm' is zero. + m = constantTimeEq(t9, fieldMSBMask) + m &= constantTimeEq(t8&t7&t6&t5&t4&t3&t2, fieldBaseMask) + m &= constantTimeGreater(t1+64+((t0+977)>>fieldBase), fieldBaseMask) + m |= t9 >> fieldMSBBits + t0 += m * 977 + t1 = (t0 >> fieldBase) + t1 + (m << 6) + t0 &= fieldBaseMask + t2 = (t1 >> fieldBase) + t2 + t1 &= fieldBaseMask + t3 = (t2 >> fieldBase) + t3 + t2 &= fieldBaseMask + t4 = (t3 >> fieldBase) + t4 + t3 &= fieldBaseMask + t5 = (t4 >> fieldBase) + t5 + t4 &= fieldBaseMask + t6 = (t5 >> fieldBase) + t6 + t5 &= fieldBaseMask + t7 = (t6 >> fieldBase) + t7 + t6 &= fieldBaseMask + t8 = (t7 >> fieldBase) + t8 + t7 &= fieldBaseMask + t9 = (t8 >> fieldBase) + t9 + t8 &= fieldBaseMask + t9 &= fieldMSBMask // Remove potential multiple of 2^256. + + // Finally, set the normalized and reduced words. + f.n[0] = t0 + f.n[1] = t1 + f.n[2] = t2 + f.n[3] = t3 + f.n[4] = t4 + f.n[5] = t5 + f.n[6] = t6 + f.n[7] = t7 + f.n[8] = t8 + f.n[9] = t9 + return f +} + +// PutBytesUnchecked unpacks the field value to a 32-byte big-endian value +// directly into the passed byte slice in constant time. The target slice must +// have at least 32 bytes available or it will panic. +// +// There is a similar function, PutBytes, which unpacks the field value into a +// 32-byte array directly. This version is provided since it can be useful +// to write directly into part of a larger buffer without needing a separate +// allocation. +// +// Preconditions: +// - The field value MUST be normalized +// - The target slice MUST have at least 32 bytes available +func (f *FieldVal) PutBytesUnchecked(b []byte) { + // Unpack the 256 total bits from the 10 uint32 words with a max of + // 26-bits per word. This could be done with a couple of for loops, + // but this unrolled version is a bit faster. Benchmarks show this is + // about 10 times faster than the variant which uses loops. + b[31] = byte(f.n[0] & eightBitsMask) + b[30] = byte((f.n[0] >> 8) & eightBitsMask) + b[29] = byte((f.n[0] >> 16) & eightBitsMask) + b[28] = byte((f.n[0]>>24)&twoBitsMask | (f.n[1]&sixBitsMask)<<2) + b[27] = byte((f.n[1] >> 6) & eightBitsMask) + b[26] = byte((f.n[1] >> 14) & eightBitsMask) + b[25] = byte((f.n[1]>>22)&fourBitsMask | (f.n[2]&fourBitsMask)<<4) + b[24] = byte((f.n[2] >> 4) & eightBitsMask) + b[23] = byte((f.n[2] >> 12) & eightBitsMask) + b[22] = byte((f.n[2]>>20)&sixBitsMask | (f.n[3]&twoBitsMask)<<6) + b[21] = byte((f.n[3] >> 2) & eightBitsMask) + b[20] = byte((f.n[3] >> 10) & eightBitsMask) + b[19] = byte((f.n[3] >> 18) & eightBitsMask) + b[18] = byte(f.n[4] & eightBitsMask) + b[17] = byte((f.n[4] >> 8) & eightBitsMask) + b[16] = byte((f.n[4] >> 16) & eightBitsMask) + b[15] = byte((f.n[4]>>24)&twoBitsMask | (f.n[5]&sixBitsMask)<<2) + b[14] = byte((f.n[5] >> 6) & eightBitsMask) + b[13] = byte((f.n[5] >> 14) & eightBitsMask) + b[12] = byte((f.n[5]>>22)&fourBitsMask | (f.n[6]&fourBitsMask)<<4) + b[11] = byte((f.n[6] >> 4) & eightBitsMask) + b[10] = byte((f.n[6] >> 12) & eightBitsMask) + b[9] = byte((f.n[6]>>20)&sixBitsMask | (f.n[7]&twoBitsMask)<<6) + b[8] = byte((f.n[7] >> 2) & eightBitsMask) + b[7] = byte((f.n[7] >> 10) & eightBitsMask) + b[6] = byte((f.n[7] >> 18) & eightBitsMask) + b[5] = byte(f.n[8] & eightBitsMask) + b[4] = byte((f.n[8] >> 8) & eightBitsMask) + b[3] = byte((f.n[8] >> 16) & eightBitsMask) + b[2] = byte((f.n[8]>>24)&twoBitsMask | (f.n[9]&sixBitsMask)<<2) + b[1] = byte((f.n[9] >> 6) & eightBitsMask) + b[0] = byte((f.n[9] >> 14) & eightBitsMask) +} + +// PutBytes unpacks the field value to a 32-byte big-endian value using the +// passed byte array in constant time. +// +// There is a similar function, PutBytesUnchecked, which unpacks the field value +// into a slice that must have at least 32 bytes available. This version is +// provided since it can be useful to write directly into an array that is type +// checked. +// +// Alternatively, there is also Bytes, which unpacks the field value into a new +// array and returns that which can sometimes be more ergonomic in applications +// that aren't concerned about an additional copy. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) PutBytes(b *[32]byte) { + f.PutBytesUnchecked(b[:]) +} + +// Bytes unpacks the field value to a 32-byte big-endian value in constant time. +// +// See PutBytes and PutBytesUnchecked for variants that allow an array or slice +// to be passed which can be useful to cut down on the number of allocations by +// allowing the caller to reuse a buffer or write directly into part of a larger +// buffer. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) Bytes() *[32]byte { + b := new([32]byte) + f.PutBytesUnchecked(b[:]) + return b +} + +// IsZeroBit returns 1 when the field value is equal to zero or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsZero for the version that returns +// a bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsZeroBit() uint32 { + // The value can only be zero if no bits are set in any of the words. + // This is a constant time implementation. + bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] | + f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return constantTimeEq(bits, 0) +} + +// IsZero returns whether or not the field value is equal to zero in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsZero() bool { + // The value can only be zero if no bits are set in any of the words. + // This is a constant time implementation. + bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] | + f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return bits == 0 +} + +// IsOneBit returns 1 when the field value is equal to one or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsOne for the version that returns a +// bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOneBit() uint32 { + // The value can only be one if the single lowest significant bit is set in + // the first word and no other bits are set in any of the other words. + // This is a constant time implementation. + bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] | + f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return constantTimeEq(bits, 0) +} + +// IsOne returns whether or not the field value is equal to one in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOne() bool { + // The value can only be one if the single lowest significant bit is set in + // the first word and no other bits are set in any of the other words. + // This is a constant time implementation. + bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] | + f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return bits == 0 +} + +// IsOddBit returns 1 when the field value is an odd number or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsOdd for the version that returns a +// bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOddBit() uint32 { + // Only odd numbers have the bottom bit set. + return f.n[0] & 1 +} + +// IsOdd returns whether or not the field value is an odd number in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOdd() bool { + // Only odd numbers have the bottom bit set. + return f.n[0]&1 == 1 +} + +// Equals returns whether or not the two field values are the same in constant +// time. +// +// Preconditions: +// - Both field values being compared MUST be normalized +func (f *FieldVal) Equals(val *FieldVal) bool { + // Xor only sets bits when they are different, so the two field values + // can only be the same if no bits are set after xoring each word. + // This is a constant time implementation. + bits := (f.n[0] ^ val.n[0]) | (f.n[1] ^ val.n[1]) | (f.n[2] ^ val.n[2]) | + (f.n[3] ^ val.n[3]) | (f.n[4] ^ val.n[4]) | (f.n[5] ^ val.n[5]) | + (f.n[6] ^ val.n[6]) | (f.n[7] ^ val.n[7]) | (f.n[8] ^ val.n[8]) | + (f.n[9] ^ val.n[9]) + + return bits == 0 +} + +// NegateVal negates the passed value and stores the result in f in constant +// time. The caller must provide the maximum magnitude of the passed value for +// a correct result. +// +// The field value is returned to support chaining. This enables syntax like: +// f.NegateVal(f2).AddInt(1) so that f = -f2 + 1. +// +// Preconditions: +// - The max magnitude MUST be 31 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 +func (f *FieldVal) NegateVal(val *FieldVal, magnitude uint32) *FieldVal { + // Negation in the field is just the prime minus the value. However, + // in order to allow negation against a field value without having to + // normalize/reduce it first, multiply by the magnitude (that is how + // "far" away it is from the normalized value) to adjust. Also, since + // negating a value pushes it one more order of magnitude away from the + // normalized range, add 1 to compensate. + // + // For some intuition here, imagine you're performing mod 12 arithmetic + // (picture a clock) and you are negating the number 7. So you start at + // 12 (which is of course 0 under mod 12) and count backwards (left on + // the clock) 7 times to arrive at 5. Notice this is just 12-7 = 5. + // Now, assume you're starting with 19, which is a number that is + // already larger than the modulus and congruent to 7 (mod 12). When a + // value is already in the desired range, its magnitude is 1. Since 19 + // is an additional "step", its magnitude (mod 12) is 2. Since any + // multiple of the modulus is congruent to zero (mod m), the answer can + // be shortcut by simply multiplying the magnitude by the modulus and + // subtracting. Keeping with the example, this would be (2*12)-19 = 5. + f.n[0] = (magnitude+1)*fieldPrimeWordZero - val.n[0] + f.n[1] = (magnitude+1)*fieldPrimeWordOne - val.n[1] + f.n[2] = (magnitude+1)*fieldBaseMask - val.n[2] + f.n[3] = (magnitude+1)*fieldBaseMask - val.n[3] + f.n[4] = (magnitude+1)*fieldBaseMask - val.n[4] + f.n[5] = (magnitude+1)*fieldBaseMask - val.n[5] + f.n[6] = (magnitude+1)*fieldBaseMask - val.n[6] + f.n[7] = (magnitude+1)*fieldBaseMask - val.n[7] + f.n[8] = (magnitude+1)*fieldBaseMask - val.n[8] + f.n[9] = (magnitude+1)*fieldMSBMask - val.n[9] + + return f +} + +// Negate negates the field value in constant time. The existing field value is +// modified. The caller must provide the maximum magnitude of the field value +// for a correct result. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Negate().AddInt(1) so that f = -f + 1. +// +// Preconditions: +// - The max magnitude MUST be 31 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 +func (f *FieldVal) Negate(magnitude uint32) *FieldVal { + return f.NegateVal(f, magnitude) +} + +// AddInt adds the passed integer to the existing field value and stores the +// result in f in constant time. This is a convenience function since it is +// fairly common to perform some arithmetic with small native integers. +// +// The field value is returned to support chaining. This enables syntax like: +// f.AddInt(1).Add(f2) so that f = f + 1 + f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 31 +// - The integer MUST be a max of 32767 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude + 1 +func (f *FieldVal) AddInt(ui uint16) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // the word and will be normalized out. + f.n[0] += uint32(ui) + + return f +} + +// Add adds the passed value to the existing field value and stores the result +// in f in constant time. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Add(f2).AddInt(1) so that f = f + f2 + 1. +// +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 32 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two individual field values +func (f *FieldVal) Add(val *FieldVal) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // each word and will be normalized out. This could obviously be done + // in a loop, but the unrolled version is faster. + f.n[0] += val.n[0] + f.n[1] += val.n[1] + f.n[2] += val.n[2] + f.n[3] += val.n[3] + f.n[4] += val.n[4] + f.n[5] += val.n[5] + f.n[6] += val.n[6] + f.n[7] += val.n[7] + f.n[8] += val.n[8] + f.n[9] += val.n[9] + + return f +} + +// Add2 adds the passed two field values together and stores the result in f in +// constant time. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.Add2(f, f2).AddInt(1) so that f3 = f + f2 + 1. +// +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 32 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two field values +func (f *FieldVal) Add2(val *FieldVal, val2 *FieldVal) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // each word and will be normalized out. This could obviously be done + // in a loop, but the unrolled version is faster. + f.n[0] = val.n[0] + val2.n[0] + f.n[1] = val.n[1] + val2.n[1] + f.n[2] = val.n[2] + val2.n[2] + f.n[3] = val.n[3] + val2.n[3] + f.n[4] = val.n[4] + val2.n[4] + f.n[5] = val.n[5] + val2.n[5] + f.n[6] = val.n[6] + val2.n[6] + f.n[7] = val.n[7] + val2.n[7] + f.n[8] = val.n[8] + val2.n[8] + f.n[9] = val.n[9] + val2.n[9] + + return f +} + +// MulInt multiplies the field value by the passed int and stores the result in +// f in constant time. Note that this function can overflow if multiplying the +// value by any of the individual words exceeds a max uint32. Therefore it is +// important that the caller ensures no overflows will occur before using this +// function. +// +// The field value is returned to support chaining. This enables syntax like: +// f.MulInt(2).Add(f2) so that f = 2 * f + f2. +// +// Preconditions: +// - The field value magnitude multiplied by given val MUST be a max of 32 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude times the provided integer val +func (f *FieldVal) MulInt(val uint8) *FieldVal { + // Since each word of the field representation can hold up to + // 32 - fieldBase extra bits which will be normalized out, it's safe + // to multiply each word without using a larger type or carry + // propagation so long as the values won't overflow a uint32. This + // could obviously be done in a loop, but the unrolled version is + // faster. + ui := uint32(val) + f.n[0] *= ui + f.n[1] *= ui + f.n[2] *= ui + f.n[3] *= ui + f.n[4] *= ui + f.n[5] *= ui + f.n[6] *= ui + f.n[7] *= ui + f.n[8] *= ui + f.n[9] *= ui + + return f +} + +// Mul multiplies the passed value to the existing field value and stores the +// result in f in constant time. Note that this function can overflow if +// multiplying any of the individual words exceeds a max uint32. In practice, +// this means the magnitude of either value involved in the multiplication must +// be a max of 8. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Mul(f2).AddInt(1) so that f = (f * f2) + 1. +// +// Preconditions: +// - Both field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Mul(val *FieldVal) *FieldVal { + return f.Mul2(f, val) +} + +// Mul2 multiplies the passed two field values together and stores the result in +// f in constant time. Note that this function can overflow if multiplying any +// of the individual words exceeds a max uint32. In practice, this means the +// magnitude of either value involved in the multiplication must be a max of 8. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.Mul2(f, f2).AddInt(1) so that f3 = (f * f2) + 1. +// +// Preconditions: +// - Both input field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Mul2(val *FieldVal, val2 *FieldVal) *FieldVal { + // This could be done with a couple of for loops and an array to store + // the intermediate terms, but this unrolled version is significantly + // faster. + + // Terms for 2^(fieldBase*0). + m := uint64(val.n[0]) * uint64(val2.n[0]) + t0 := m & fieldBaseMask + + // Terms for 2^(fieldBase*1). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[1]) + + uint64(val.n[1])*uint64(val2.n[0]) + t1 := m & fieldBaseMask + + // Terms for 2^(fieldBase*2). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[2]) + + uint64(val.n[1])*uint64(val2.n[1]) + + uint64(val.n[2])*uint64(val2.n[0]) + t2 := m & fieldBaseMask + + // Terms for 2^(fieldBase*3). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[3]) + + uint64(val.n[1])*uint64(val2.n[2]) + + uint64(val.n[2])*uint64(val2.n[1]) + + uint64(val.n[3])*uint64(val2.n[0]) + t3 := m & fieldBaseMask + + // Terms for 2^(fieldBase*4). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[4]) + + uint64(val.n[1])*uint64(val2.n[3]) + + uint64(val.n[2])*uint64(val2.n[2]) + + uint64(val.n[3])*uint64(val2.n[1]) + + uint64(val.n[4])*uint64(val2.n[0]) + t4 := m & fieldBaseMask + + // Terms for 2^(fieldBase*5). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[5]) + + uint64(val.n[1])*uint64(val2.n[4]) + + uint64(val.n[2])*uint64(val2.n[3]) + + uint64(val.n[3])*uint64(val2.n[2]) + + uint64(val.n[4])*uint64(val2.n[1]) + + uint64(val.n[5])*uint64(val2.n[0]) + t5 := m & fieldBaseMask + + // Terms for 2^(fieldBase*6). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[6]) + + uint64(val.n[1])*uint64(val2.n[5]) + + uint64(val.n[2])*uint64(val2.n[4]) + + uint64(val.n[3])*uint64(val2.n[3]) + + uint64(val.n[4])*uint64(val2.n[2]) + + uint64(val.n[5])*uint64(val2.n[1]) + + uint64(val.n[6])*uint64(val2.n[0]) + t6 := m & fieldBaseMask + + // Terms for 2^(fieldBase*7). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[7]) + + uint64(val.n[1])*uint64(val2.n[6]) + + uint64(val.n[2])*uint64(val2.n[5]) + + uint64(val.n[3])*uint64(val2.n[4]) + + uint64(val.n[4])*uint64(val2.n[3]) + + uint64(val.n[5])*uint64(val2.n[2]) + + uint64(val.n[6])*uint64(val2.n[1]) + + uint64(val.n[7])*uint64(val2.n[0]) + t7 := m & fieldBaseMask + + // Terms for 2^(fieldBase*8). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[8]) + + uint64(val.n[1])*uint64(val2.n[7]) + + uint64(val.n[2])*uint64(val2.n[6]) + + uint64(val.n[3])*uint64(val2.n[5]) + + uint64(val.n[4])*uint64(val2.n[4]) + + uint64(val.n[5])*uint64(val2.n[3]) + + uint64(val.n[6])*uint64(val2.n[2]) + + uint64(val.n[7])*uint64(val2.n[1]) + + uint64(val.n[8])*uint64(val2.n[0]) + t8 := m & fieldBaseMask + + // Terms for 2^(fieldBase*9). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[9]) + + uint64(val.n[1])*uint64(val2.n[8]) + + uint64(val.n[2])*uint64(val2.n[7]) + + uint64(val.n[3])*uint64(val2.n[6]) + + uint64(val.n[4])*uint64(val2.n[5]) + + uint64(val.n[5])*uint64(val2.n[4]) + + uint64(val.n[6])*uint64(val2.n[3]) + + uint64(val.n[7])*uint64(val2.n[2]) + + uint64(val.n[8])*uint64(val2.n[1]) + + uint64(val.n[9])*uint64(val2.n[0]) + t9 := m & fieldBaseMask + + // Terms for 2^(fieldBase*10). + m = (m >> fieldBase) + + uint64(val.n[1])*uint64(val2.n[9]) + + uint64(val.n[2])*uint64(val2.n[8]) + + uint64(val.n[3])*uint64(val2.n[7]) + + uint64(val.n[4])*uint64(val2.n[6]) + + uint64(val.n[5])*uint64(val2.n[5]) + + uint64(val.n[6])*uint64(val2.n[4]) + + uint64(val.n[7])*uint64(val2.n[3]) + + uint64(val.n[8])*uint64(val2.n[2]) + + uint64(val.n[9])*uint64(val2.n[1]) + t10 := m & fieldBaseMask + + // Terms for 2^(fieldBase*11). + m = (m >> fieldBase) + + uint64(val.n[2])*uint64(val2.n[9]) + + uint64(val.n[3])*uint64(val2.n[8]) + + uint64(val.n[4])*uint64(val2.n[7]) + + uint64(val.n[5])*uint64(val2.n[6]) + + uint64(val.n[6])*uint64(val2.n[5]) + + uint64(val.n[7])*uint64(val2.n[4]) + + uint64(val.n[8])*uint64(val2.n[3]) + + uint64(val.n[9])*uint64(val2.n[2]) + t11 := m & fieldBaseMask + + // Terms for 2^(fieldBase*12). + m = (m >> fieldBase) + + uint64(val.n[3])*uint64(val2.n[9]) + + uint64(val.n[4])*uint64(val2.n[8]) + + uint64(val.n[5])*uint64(val2.n[7]) + + uint64(val.n[6])*uint64(val2.n[6]) + + uint64(val.n[7])*uint64(val2.n[5]) + + uint64(val.n[8])*uint64(val2.n[4]) + + uint64(val.n[9])*uint64(val2.n[3]) + t12 := m & fieldBaseMask + + // Terms for 2^(fieldBase*13). + m = (m >> fieldBase) + + uint64(val.n[4])*uint64(val2.n[9]) + + uint64(val.n[5])*uint64(val2.n[8]) + + uint64(val.n[6])*uint64(val2.n[7]) + + uint64(val.n[7])*uint64(val2.n[6]) + + uint64(val.n[8])*uint64(val2.n[5]) + + uint64(val.n[9])*uint64(val2.n[4]) + t13 := m & fieldBaseMask + + // Terms for 2^(fieldBase*14). + m = (m >> fieldBase) + + uint64(val.n[5])*uint64(val2.n[9]) + + uint64(val.n[6])*uint64(val2.n[8]) + + uint64(val.n[7])*uint64(val2.n[7]) + + uint64(val.n[8])*uint64(val2.n[6]) + + uint64(val.n[9])*uint64(val2.n[5]) + t14 := m & fieldBaseMask + + // Terms for 2^(fieldBase*15). + m = (m >> fieldBase) + + uint64(val.n[6])*uint64(val2.n[9]) + + uint64(val.n[7])*uint64(val2.n[8]) + + uint64(val.n[8])*uint64(val2.n[7]) + + uint64(val.n[9])*uint64(val2.n[6]) + t15 := m & fieldBaseMask + + // Terms for 2^(fieldBase*16). + m = (m >> fieldBase) + + uint64(val.n[7])*uint64(val2.n[9]) + + uint64(val.n[8])*uint64(val2.n[8]) + + uint64(val.n[9])*uint64(val2.n[7]) + t16 := m & fieldBaseMask + + // Terms for 2^(fieldBase*17). + m = (m >> fieldBase) + + uint64(val.n[8])*uint64(val2.n[9]) + + uint64(val.n[9])*uint64(val2.n[8]) + t17 := m & fieldBaseMask + + // Terms for 2^(fieldBase*18). + m = (m >> fieldBase) + uint64(val.n[9])*uint64(val2.n[9]) + t18 := m & fieldBaseMask + + // What's left is for 2^(fieldBase*19). + t19 := m >> fieldBase + + // At this point, all of the terms are grouped into their respective + // base. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved per the provided algorithm. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // Since each word is in base 26, the upper terms (t10 and up) start + // at 260 bits (versus the final desired range of 256 bits), so the + // field representation of 'c' from above needs to be adjusted for the + // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 = + // 68719492368. Thus, the adjusted field representation of 'c' is: + // n[0] = 977 * 16 = 15632 + // n[1] = 64 * 16 = 1024 + // That is to say (2^26 * 1024) + 15632 = 68719492368 + // + // To reduce the final term, t19, the entire 'c' value is needed instead + // of only n[0] because there are no more terms left to handle n[1]. + // This means there might be some magnitude left in the upper bits that + // is handled below. + m = t0 + t10*15632 + t0 = m & fieldBaseMask + m = (m >> fieldBase) + t1 + t10*1024 + t11*15632 + t1 = m & fieldBaseMask + m = (m >> fieldBase) + t2 + t11*1024 + t12*15632 + t2 = m & fieldBaseMask + m = (m >> fieldBase) + t3 + t12*1024 + t13*15632 + t3 = m & fieldBaseMask + m = (m >> fieldBase) + t4 + t13*1024 + t14*15632 + t4 = m & fieldBaseMask + m = (m >> fieldBase) + t5 + t14*1024 + t15*15632 + t5 = m & fieldBaseMask + m = (m >> fieldBase) + t6 + t15*1024 + t16*15632 + t6 = m & fieldBaseMask + m = (m >> fieldBase) + t7 + t16*1024 + t17*15632 + t7 = m & fieldBaseMask + m = (m >> fieldBase) + t8 + t17*1024 + t18*15632 + t8 = m & fieldBaseMask + m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368 + t9 = m & fieldMSBMask + m >>= fieldMSBBits + + // At this point, if the magnitude is greater than 0, the overall value + // is greater than the max possible 256-bit value. In particular, it is + // "how many times larger" than the max value it is. + // + // The algorithm presented in [HAC] section 14.3.4 repeats until the + // quotient is zero. However, due to the above, we already know at + // least how many times we would need to repeat as it's the value + // currently in m. Thus we can simply multiply the magnitude by the + // field representation of the prime and do a single iteration. Notice + // that nothing will be changed when the magnitude is zero, so we could + // skip this in that case, however always running regardless allows it + // to run in constant time. The final result will be in the range + // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a + // magnitude of 1, but it is denormalized. + d := t0 + m*977 + f.n[0] = uint32(d & fieldBaseMask) + d = (d >> fieldBase) + t1 + m*64 + f.n[1] = uint32(d & fieldBaseMask) + f.n[2] = uint32((d >> fieldBase) + t2) + f.n[3] = uint32(t3) + f.n[4] = uint32(t4) + f.n[5] = uint32(t5) + f.n[6] = uint32(t6) + f.n[7] = uint32(t7) + f.n[8] = uint32(t8) + f.n[9] = uint32(t9) + + return f +} + +// SquareRootVal either calculates the square root of the passed value when it +// exists or the square root of the negation of the value when it does not exist +// and stores the result in f in constant time. The return flag is true when +// the calculated square root is for the passed value itself and false when it +// is for its negation. +// +// Note that this function can overflow if multiplying any of the individual +// words exceeds a max uint32. In practice, this means the magnitude of the +// field must be a max of 8 to prevent overflow. The magnitude of the result +// will be 1. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) SquareRootVal(val *FieldVal) bool { + // This uses the Tonelli-Shanks method for calculating the square root of + // the value when it exists. The key principles of the method follow. + // + // Fermat's little theorem states that for a nonzero number 'a' and prime + // 'p', a^(p-1) ≡ 1 (mod p). + // + // Further, Euler's criterion states that an integer 'a' has a square root + // (aka is a quadratic residue) modulo a prime if a^((p-1)/2) ≡ 1 (mod p) + // and, conversely, when it does NOT have a square root (aka 'a' is a + // non-residue) a^((p-1)/2) ≡ -1 (mod p). + // + // This can be seen by considering that Fermat's little theorem can be + // written as (a^((p-1)/2) - 1)(a^((p-1)/2) + 1) ≡ 0 (mod p). Therefore, + // one of the two factors must be 0. Then, when a ≡ x^2 (aka 'a' is a + // quadratic residue), (x^2)^((p-1)/2) ≡ x^(p-1) ≡ 1 (mod p) which implies + // the first factor must be zero. Finally, per Lagrange's theorem, the + // non-residues are the only remaining possible solutions and thus must make + // the second factor zero to satisfy Fermat's little theorem implying that + // a^((p-1)/2) ≡ -1 (mod p) for that case. + // + // The Tonelli-Shanks method uses these facts along with factoring out + // powers of two to solve a congruence that results in either the solution + // when the square root exists or the square root of the negation of the + // value when it does not. In the case of primes that are ≡ 3 (mod 4), the + // possible solutions are r = ±a^((p+1)/4) (mod p). Therefore, either r^2 ≡ + // a (mod p) is true in which case ±r are the two solutions, or r^2 ≡ -a + // (mod p) in which case 'a' is a non-residue and there are no solutions. + // + // The secp256k1 prime is ≡ 3 (mod 4), so this result applies. + // + // In other words, calculate a^((p+1)/4) and then square it and check it + // against the original value to determine if it is actually the square + // root. + // + // In order to efficiently compute a^((p+1)/4), (p+1)/4 needs to be split + // into a sequence of squares and multiplications that minimizes the number + // of multiplications needed (since they are more costly than squarings). + // + // The secp256k1 prime + 1 / 4 is 2^254 - 2^30 - 244. In binary, that is: + // + // 00111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 10111111 11111111 11111111 00001100 + // + // Notice that can be broken up into three windows of consecutive 1s (in + // order of least to most significant) as: + // + // 6-bit window with two bits set (bits 4, 5, 6, 7 unset) + // 23-bit window with 22 bits set (bit 30 unset) + // 223-bit window with all 223 bits set + // + // Thus, the groups of 1 bits in each window forms the set: + // S = {2, 22, 223}. + // + // The strategy is to calculate a^(2^n - 1) for each grouping via an + // addition chain with a sliding window. + // + // The addition chain used is (credits to Peter Dettman): + // (0,0),(1,0),(2,2),(3,2),(4,1),(5,5),(6,6),(7,7),(8,8),(9,7),(10,2) + // => 2^1 2^[2] 2^3 2^6 2^9 2^11 2^[22] 2^44 2^88 2^176 2^220 2^[223] + // + // This has a cost of 254 field squarings and 13 field multiplications. + var a, a2, a3, a6, a9, a11, a22, a44, a88, a176, a220, a223 FieldVal + a.Set(val) + a2.SquareVal(&a).Mul(&a) // a2 = a^(2^2 - 1) + a3.SquareVal(&a2).Mul(&a) // a3 = a^(2^3 - 1) + a6.SquareVal(&a3).Square().Square() // a6 = a^(2^6 - 2^3) + a6.Mul(&a3) // a6 = a^(2^6 - 1) + a9.SquareVal(&a6).Square().Square() // a9 = a^(2^9 - 2^3) + a9.Mul(&a3) // a9 = a^(2^9 - 1) + a11.SquareVal(&a9).Square() // a11 = a^(2^11 - 2^2) + a11.Mul(&a2) // a11 = a^(2^11 - 1) + a22.SquareVal(&a11).Square().Square().Square().Square() // a22 = a^(2^16 - 2^5) + a22.Square().Square().Square().Square().Square() // a22 = a^(2^21 - 2^10) + a22.Square() // a22 = a^(2^22 - 2^11) + a22.Mul(&a11) // a22 = a^(2^22 - 1) + a44.SquareVal(&a22).Square().Square().Square().Square() // a44 = a^(2^27 - 2^5) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^32 - 2^10) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^37 - 2^15) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^42 - 2^20) + a44.Square().Square() // a44 = a^(2^44 - 2^22) + a44.Mul(&a22) // a44 = a^(2^44 - 1) + a88.SquareVal(&a44).Square().Square().Square().Square() // a88 = a^(2^49 - 2^5) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^54 - 2^10) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^59 - 2^15) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^64 - 2^20) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^69 - 2^25) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^74 - 2^30) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^79 - 2^35) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^84 - 2^40) + a88.Square().Square().Square().Square() // a88 = a^(2^88 - 2^44) + a88.Mul(&a44) // a88 = a^(2^88 - 1) + a176.SquareVal(&a88).Square().Square().Square().Square() // a176 = a^(2^93 - 2^5) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^98 - 2^10) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^103 - 2^15) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^108 - 2^20) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^113 - 2^25) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^118 - 2^30) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^123 - 2^35) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^128 - 2^40) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^133 - 2^45) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^138 - 2^50) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^143 - 2^55) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^148 - 2^60) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^153 - 2^65) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^158 - 2^70) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^163 - 2^75) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^168 - 2^80) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^173 - 2^85) + a176.Square().Square().Square() // a176 = a^(2^176 - 2^88) + a176.Mul(&a88) // a176 = a^(2^176 - 1) + a220.SquareVal(&a176).Square().Square().Square().Square() // a220 = a^(2^181 - 2^5) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^186 - 2^10) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^191 - 2^15) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^196 - 2^20) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^201 - 2^25) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^206 - 2^30) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^211 - 2^35) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^216 - 2^40) + a220.Square().Square().Square().Square() // a220 = a^(2^220 - 2^44) + a220.Mul(&a44) // a220 = a^(2^220 - 1) + a223.SquareVal(&a220).Square().Square() // a223 = a^(2^223 - 2^3) + a223.Mul(&a3) // a223 = a^(2^223 - 1) + + f.SquareVal(&a223).Square().Square().Square().Square() // f = a^(2^228 - 2^5) + f.Square().Square().Square().Square().Square() // f = a^(2^233 - 2^10) + f.Square().Square().Square().Square().Square() // f = a^(2^238 - 2^15) + f.Square().Square().Square().Square().Square() // f = a^(2^243 - 2^20) + f.Square().Square().Square() // f = a^(2^246 - 2^23) + f.Mul(&a22) // f = a^(2^246 - 2^22 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^251 - 2^27 - 2^5) + f.Square() // f = a^(2^252 - 2^28 - 2^6) + f.Mul(&a2) // f = a^(2^252 - 2^28 - 2^6 - 2^1 - 1) + f.Square().Square() // f = a^(2^254 - 2^30 - 2^8 - 2^3 - 2^2) + // // = a^(2^254 - 2^30 - 244) + // // = a^((p+1)/4) + + // Ensure the calculated result is actually the square root by squaring it + // and checking against the original value. + var sqr FieldVal + return sqr.SquareVal(f).Normalize().Equals(val.Normalize()) +} + +// Square squares the field value in constant time. The existing field value is +// modified. Note that this function can overflow if multiplying any of the +// individual words exceeds a max uint32. In practice, this means the magnitude +// of the field must be a max of 8 to prevent overflow. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Square().Mul(f2) so that f = f^2 * f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Square() *FieldVal { + return f.SquareVal(f) +} + +// SquareVal squares the passed value and stores the result in f in constant +// time. Note that this function can overflow if multiplying any of the +// individual words exceeds a max uint32. In practice, this means the magnitude +// of the field being squared must be a max of 8 to prevent overflow. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.SquareVal(f).Mul(f) so that f3 = f^2 * f = f^3. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) SquareVal(val *FieldVal) *FieldVal { + // This could be done with a couple of for loops and an array to store + // the intermediate terms, but this unrolled version is significantly + // faster. + + // Terms for 2^(fieldBase*0). + m := uint64(val.n[0]) * uint64(val.n[0]) + t0 := m & fieldBaseMask + + // Terms for 2^(fieldBase*1). + m = (m >> fieldBase) + 2*uint64(val.n[0])*uint64(val.n[1]) + t1 := m & fieldBaseMask + + // Terms for 2^(fieldBase*2). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[2]) + + uint64(val.n[1])*uint64(val.n[1]) + t2 := m & fieldBaseMask + + // Terms for 2^(fieldBase*3). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[3]) + + 2*uint64(val.n[1])*uint64(val.n[2]) + t3 := m & fieldBaseMask + + // Terms for 2^(fieldBase*4). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[4]) + + 2*uint64(val.n[1])*uint64(val.n[3]) + + uint64(val.n[2])*uint64(val.n[2]) + t4 := m & fieldBaseMask + + // Terms for 2^(fieldBase*5). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[5]) + + 2*uint64(val.n[1])*uint64(val.n[4]) + + 2*uint64(val.n[2])*uint64(val.n[3]) + t5 := m & fieldBaseMask + + // Terms for 2^(fieldBase*6). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[6]) + + 2*uint64(val.n[1])*uint64(val.n[5]) + + 2*uint64(val.n[2])*uint64(val.n[4]) + + uint64(val.n[3])*uint64(val.n[3]) + t6 := m & fieldBaseMask + + // Terms for 2^(fieldBase*7). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[7]) + + 2*uint64(val.n[1])*uint64(val.n[6]) + + 2*uint64(val.n[2])*uint64(val.n[5]) + + 2*uint64(val.n[3])*uint64(val.n[4]) + t7 := m & fieldBaseMask + + // Terms for 2^(fieldBase*8). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[8]) + + 2*uint64(val.n[1])*uint64(val.n[7]) + + 2*uint64(val.n[2])*uint64(val.n[6]) + + 2*uint64(val.n[3])*uint64(val.n[5]) + + uint64(val.n[4])*uint64(val.n[4]) + t8 := m & fieldBaseMask + + // Terms for 2^(fieldBase*9). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[9]) + + 2*uint64(val.n[1])*uint64(val.n[8]) + + 2*uint64(val.n[2])*uint64(val.n[7]) + + 2*uint64(val.n[3])*uint64(val.n[6]) + + 2*uint64(val.n[4])*uint64(val.n[5]) + t9 := m & fieldBaseMask + + // Terms for 2^(fieldBase*10). + m = (m >> fieldBase) + + 2*uint64(val.n[1])*uint64(val.n[9]) + + 2*uint64(val.n[2])*uint64(val.n[8]) + + 2*uint64(val.n[3])*uint64(val.n[7]) + + 2*uint64(val.n[4])*uint64(val.n[6]) + + uint64(val.n[5])*uint64(val.n[5]) + t10 := m & fieldBaseMask + + // Terms for 2^(fieldBase*11). + m = (m >> fieldBase) + + 2*uint64(val.n[2])*uint64(val.n[9]) + + 2*uint64(val.n[3])*uint64(val.n[8]) + + 2*uint64(val.n[4])*uint64(val.n[7]) + + 2*uint64(val.n[5])*uint64(val.n[6]) + t11 := m & fieldBaseMask + + // Terms for 2^(fieldBase*12). + m = (m >> fieldBase) + + 2*uint64(val.n[3])*uint64(val.n[9]) + + 2*uint64(val.n[4])*uint64(val.n[8]) + + 2*uint64(val.n[5])*uint64(val.n[7]) + + uint64(val.n[6])*uint64(val.n[6]) + t12 := m & fieldBaseMask + + // Terms for 2^(fieldBase*13). + m = (m >> fieldBase) + + 2*uint64(val.n[4])*uint64(val.n[9]) + + 2*uint64(val.n[5])*uint64(val.n[8]) + + 2*uint64(val.n[6])*uint64(val.n[7]) + t13 := m & fieldBaseMask + + // Terms for 2^(fieldBase*14). + m = (m >> fieldBase) + + 2*uint64(val.n[5])*uint64(val.n[9]) + + 2*uint64(val.n[6])*uint64(val.n[8]) + + uint64(val.n[7])*uint64(val.n[7]) + t14 := m & fieldBaseMask + + // Terms for 2^(fieldBase*15). + m = (m >> fieldBase) + + 2*uint64(val.n[6])*uint64(val.n[9]) + + 2*uint64(val.n[7])*uint64(val.n[8]) + t15 := m & fieldBaseMask + + // Terms for 2^(fieldBase*16). + m = (m >> fieldBase) + + 2*uint64(val.n[7])*uint64(val.n[9]) + + uint64(val.n[8])*uint64(val.n[8]) + t16 := m & fieldBaseMask + + // Terms for 2^(fieldBase*17). + m = (m >> fieldBase) + 2*uint64(val.n[8])*uint64(val.n[9]) + t17 := m & fieldBaseMask + + // Terms for 2^(fieldBase*18). + m = (m >> fieldBase) + uint64(val.n[9])*uint64(val.n[9]) + t18 := m & fieldBaseMask + + // What's left is for 2^(fieldBase*19). + t19 := m >> fieldBase + + // At this point, all of the terms are grouped into their respective + // base. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved per the provided algorithm. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // Since each word is in base 26, the upper terms (t10 and up) start + // at 260 bits (versus the final desired range of 256 bits), so the + // field representation of 'c' from above needs to be adjusted for the + // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 = + // 68719492368. Thus, the adjusted field representation of 'c' is: + // n[0] = 977 * 16 = 15632 + // n[1] = 64 * 16 = 1024 + // That is to say (2^26 * 1024) + 15632 = 68719492368 + // + // To reduce the final term, t19, the entire 'c' value is needed instead + // of only n[0] because there are no more terms left to handle n[1]. + // This means there might be some magnitude left in the upper bits that + // is handled below. + m = t0 + t10*15632 + t0 = m & fieldBaseMask + m = (m >> fieldBase) + t1 + t10*1024 + t11*15632 + t1 = m & fieldBaseMask + m = (m >> fieldBase) + t2 + t11*1024 + t12*15632 + t2 = m & fieldBaseMask + m = (m >> fieldBase) + t3 + t12*1024 + t13*15632 + t3 = m & fieldBaseMask + m = (m >> fieldBase) + t4 + t13*1024 + t14*15632 + t4 = m & fieldBaseMask + m = (m >> fieldBase) + t5 + t14*1024 + t15*15632 + t5 = m & fieldBaseMask + m = (m >> fieldBase) + t6 + t15*1024 + t16*15632 + t6 = m & fieldBaseMask + m = (m >> fieldBase) + t7 + t16*1024 + t17*15632 + t7 = m & fieldBaseMask + m = (m >> fieldBase) + t8 + t17*1024 + t18*15632 + t8 = m & fieldBaseMask + m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368 + t9 = m & fieldMSBMask + m >>= fieldMSBBits + + // At this point, if the magnitude is greater than 0, the overall value + // is greater than the max possible 256-bit value. In particular, it is + // "how many times larger" than the max value it is. + // + // The algorithm presented in [HAC] section 14.3.4 repeats until the + // quotient is zero. However, due to the above, we already know at + // least how many times we would need to repeat as it's the value + // currently in m. Thus we can simply multiply the magnitude by the + // field representation of the prime and do a single iteration. Notice + // that nothing will be changed when the magnitude is zero, so we could + // skip this in that case, however always running regardless allows it + // to run in constant time. The final result will be in the range + // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a + // magnitude of 1, but it is denormalized. + n := t0 + m*977 + f.n[0] = uint32(n & fieldBaseMask) + n = (n >> fieldBase) + t1 + m*64 + f.n[1] = uint32(n & fieldBaseMask) + f.n[2] = uint32((n >> fieldBase) + t2) + f.n[3] = uint32(t3) + f.n[4] = uint32(t4) + f.n[5] = uint32(t5) + f.n[6] = uint32(t6) + f.n[7] = uint32(t7) + f.n[8] = uint32(t8) + f.n[9] = uint32(t9) + + return f +} + +// Inverse finds the modular multiplicative inverse of the field value in +// constant time. The existing field value is modified. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Inverse().Mul(f2) so that f = f^-1 * f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Inverse() *FieldVal { + // Fermat's little theorem states that for a nonzero number 'a' and prime + // 'p', a^(p-1) ≡ 1 (mod p). Multiplying both sides of the equation by the + // multiplicative inverse a^-1 yields a^(p-2) ≡ a^-1 (mod p). Thus, a^(p-2) + // is the multiplicative inverse. + // + // In order to efficiently compute a^(p-2), p-2 needs to be split into a + // sequence of squares and multiplications that minimizes the number of + // multiplications needed (since they are more costly than squarings). + // Intermediate results are saved and reused as well. + // + // The secp256k1 prime - 2 is 2^256 - 4294968275. In binary, that is: + // + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111110 + // 11111111 11111111 11111100 00101101 + // + // Notice that can be broken up into five windows of consecutive 1s (in + // order of least to most significant) as: + // + // 2-bit window with 1 bit set (bit 1 unset) + // 3-bit window with 2 bits set (bit 4 unset) + // 5-bit window with 1 bit set (bits 6, 7, 8, 9 unset) + // 23-bit window with 22 bits set (bit 32 unset) + // 223-bit window with all 223 bits set + // + // Thus, the groups of 1 bits in each window forms the set: + // S = {1, 2, 22, 223}. + // + // The strategy is to calculate a^(2^n - 1) for each grouping via an + // addition chain with a sliding window. + // + // The addition chain used is (credits to Peter Dettman): + // (0,0),(1,0),(2,2),(3,2),(4,1),(5,5),(6,6),(7,7),(8,8),(9,7),(10,2) + // => 2^[1] 2^[2] 2^3 2^6 2^9 2^11 2^[22] 2^44 2^88 2^176 2^220 2^[223] + // + // This has a cost of 255 field squarings and 15 field multiplications. + var a, a2, a3, a6, a9, a11, a22, a44, a88, a176, a220, a223 FieldVal + a.Set(f) + a2.SquareVal(&a).Mul(&a) // a2 = a^(2^2 - 1) + a3.SquareVal(&a2).Mul(&a) // a3 = a^(2^3 - 1) + a6.SquareVal(&a3).Square().Square() // a6 = a^(2^6 - 2^3) + a6.Mul(&a3) // a6 = a^(2^6 - 1) + a9.SquareVal(&a6).Square().Square() // a9 = a^(2^9 - 2^3) + a9.Mul(&a3) // a9 = a^(2^9 - 1) + a11.SquareVal(&a9).Square() // a11 = a^(2^11 - 2^2) + a11.Mul(&a2) // a11 = a^(2^11 - 1) + a22.SquareVal(&a11).Square().Square().Square().Square() // a22 = a^(2^16 - 2^5) + a22.Square().Square().Square().Square().Square() // a22 = a^(2^21 - 2^10) + a22.Square() // a22 = a^(2^22 - 2^11) + a22.Mul(&a11) // a22 = a^(2^22 - 1) + a44.SquareVal(&a22).Square().Square().Square().Square() // a44 = a^(2^27 - 2^5) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^32 - 2^10) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^37 - 2^15) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^42 - 2^20) + a44.Square().Square() // a44 = a^(2^44 - 2^22) + a44.Mul(&a22) // a44 = a^(2^44 - 1) + a88.SquareVal(&a44).Square().Square().Square().Square() // a88 = a^(2^49 - 2^5) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^54 - 2^10) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^59 - 2^15) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^64 - 2^20) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^69 - 2^25) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^74 - 2^30) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^79 - 2^35) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^84 - 2^40) + a88.Square().Square().Square().Square() // a88 = a^(2^88 - 2^44) + a88.Mul(&a44) // a88 = a^(2^88 - 1) + a176.SquareVal(&a88).Square().Square().Square().Square() // a176 = a^(2^93 - 2^5) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^98 - 2^10) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^103 - 2^15) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^108 - 2^20) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^113 - 2^25) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^118 - 2^30) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^123 - 2^35) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^128 - 2^40) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^133 - 2^45) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^138 - 2^50) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^143 - 2^55) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^148 - 2^60) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^153 - 2^65) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^158 - 2^70) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^163 - 2^75) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^168 - 2^80) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^173 - 2^85) + a176.Square().Square().Square() // a176 = a^(2^176 - 2^88) + a176.Mul(&a88) // a176 = a^(2^176 - 1) + a220.SquareVal(&a176).Square().Square().Square().Square() // a220 = a^(2^181 - 2^5) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^186 - 2^10) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^191 - 2^15) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^196 - 2^20) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^201 - 2^25) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^206 - 2^30) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^211 - 2^35) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^216 - 2^40) + a220.Square().Square().Square().Square() // a220 = a^(2^220 - 2^44) + a220.Mul(&a44) // a220 = a^(2^220 - 1) + a223.SquareVal(&a220).Square().Square() // a223 = a^(2^223 - 2^3) + a223.Mul(&a3) // a223 = a^(2^223 - 1) + + f.SquareVal(&a223).Square().Square().Square().Square() // f = a^(2^228 - 2^5) + f.Square().Square().Square().Square().Square() // f = a^(2^233 - 2^10) + f.Square().Square().Square().Square().Square() // f = a^(2^238 - 2^15) + f.Square().Square().Square().Square().Square() // f = a^(2^243 - 2^20) + f.Square().Square().Square() // f = a^(2^246 - 2^23) + f.Mul(&a22) // f = a^(2^246 - 4194305) + f.Square().Square().Square().Square().Square() // f = a^(2^251 - 134217760) + f.Mul(&a) // f = a^(2^251 - 134217759) + f.Square().Square().Square() // f = a^(2^254 - 1073742072) + f.Mul(&a2) // f = a^(2^254 - 1073742069) + f.Square().Square() // f = a^(2^256 - 4294968276) + return f.Mul(&a) // f = a^(2^256 - 4294968275) = a^(p-2) +} + +// IsGtOrEqPrimeMinusOrder returns whether or not the field value is greater +// than or equal to the field prime minus the secp256k1 group order in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsGtOrEqPrimeMinusOrder() bool { + // The secp256k1 prime is equivalent to 2^256 - 4294968273 and the group + // order is 2^256 - 432420386565659656852420866394968145599. Thus, + // the prime minus the group order is: + // 432420386565659656852420866390673177326 + // + // In hex that is: + // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da172 2fc9baee + // + // Converting that to field representation (base 2^26) is: + // + // n[0] = 0x03c9baee + // n[1] = 0x03685c8b + // n[2] = 0x01fc4402 + // n[3] = 0x006542dd + // n[4] = 0x01455123 + // + // This can be verified with the following test code: + // pMinusN := new(big.Int).Sub(curveParams.P, curveParams.N) + // var fv FieldVal + // fv.SetByteSlice(pMinusN.Bytes()) + // t.Logf("%x", fv.n) + // + // Outputs: [3c9baee 3685c8b 1fc4402 6542dd 1455123 0 0 0 0 0] + const ( + pMinusNWordZero = 0x03c9baee + pMinusNWordOne = 0x03685c8b + pMinusNWordTwo = 0x01fc4402 + pMinusNWordThree = 0x006542dd + pMinusNWordFour = 0x01455123 + pMinusNWordFive = 0x00000000 + pMinusNWordSix = 0x00000000 + pMinusNWordSeven = 0x00000000 + pMinusNWordEight = 0x00000000 + pMinusNWordNine = 0x00000000 + ) + + // The intuition here is that the value is greater than field prime minus + // the group order if one of the higher individual words is greater than the + // corresponding word and all higher words in the value are equal. + result := constantTimeGreater(f.n[9], pMinusNWordNine) + highWordsEqual := constantTimeEq(f.n[9], pMinusNWordNine) + result |= highWordsEqual & constantTimeGreater(f.n[8], pMinusNWordEight) + highWordsEqual &= constantTimeEq(f.n[8], pMinusNWordEight) + result |= highWordsEqual & constantTimeGreater(f.n[7], pMinusNWordSeven) + highWordsEqual &= constantTimeEq(f.n[7], pMinusNWordSeven) + result |= highWordsEqual & constantTimeGreater(f.n[6], pMinusNWordSix) + highWordsEqual &= constantTimeEq(f.n[6], pMinusNWordSix) + result |= highWordsEqual & constantTimeGreater(f.n[5], pMinusNWordFive) + highWordsEqual &= constantTimeEq(f.n[5], pMinusNWordFive) + result |= highWordsEqual & constantTimeGreater(f.n[4], pMinusNWordFour) + highWordsEqual &= constantTimeEq(f.n[4], pMinusNWordFour) + result |= highWordsEqual & constantTimeGreater(f.n[3], pMinusNWordThree) + highWordsEqual &= constantTimeEq(f.n[3], pMinusNWordThree) + result |= highWordsEqual & constantTimeGreater(f.n[2], pMinusNWordTwo) + highWordsEqual &= constantTimeEq(f.n[2], pMinusNWordTwo) + result |= highWordsEqual & constantTimeGreater(f.n[1], pMinusNWordOne) + highWordsEqual &= constantTimeEq(f.n[1], pMinusNWordOne) + result |= highWordsEqual & constantTimeGreaterOrEq(f.n[0], pMinusNWordZero) + + return result != 0 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go new file mode 100644 index 0000000000..91c3d37769 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/loadprecomputed.go @@ -0,0 +1,91 @@ +// Copyright 2015 The btcsuite developers +// Copyright (c) 2015-2022 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "compress/zlib" + "encoding/base64" + "io" + "strings" + "sync" +) + +//go:generate go run genprecomps.go + +// bytePointTable describes a table used to house pre-computed values for +// accelerating scalar base multiplication. +type bytePointTable [32][256]JacobianPoint + +// compressedBytePointsFn is set to a real function by the code generation to +// return the compressed pre-computed values for accelerating scalar base +// multiplication. +var compressedBytePointsFn func() string + +// s256BytePoints houses pre-computed values used to accelerate scalar base +// multiplication such that they are only loaded on first use. +var s256BytePoints = func() func() *bytePointTable { + // mustLoadBytePoints decompresses and deserializes the pre-computed byte + // points used to accelerate scalar base multiplication for the secp256k1 + // curve. + // + // This approach is used since it allows the compile to use significantly + // less ram and be performed much faster than it is with hard-coding the + // final in-memory data structure. At the same time, it is quite fast to + // generate the in-memory data structure on first use with this approach + // versus computing the table. + // + // It will panic on any errors because the data is hard coded and thus any + // errors means something is wrong in the source code. + var data *bytePointTable + mustLoadBytePoints := func() { + // There will be no byte points to load when generating them. + if compressedBytePointsFn == nil { + return + } + bp := compressedBytePointsFn() + + // Decompress the pre-computed table used to accelerate scalar base + // multiplication. + decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp)) + r, err := zlib.NewReader(decoder) + if err != nil { + panic(err) + } + serialized, err := io.ReadAll(r) + if err != nil { + panic(err) + } + + // Deserialize the precomputed byte points and set the memory table to + // them. + offset := 0 + var bytePoints bytePointTable + for byteNum := 0; byteNum < len(bytePoints); byteNum++ { + // All points in this window. + for i := 0; i < len(bytePoints[byteNum]); i++ { + p := &bytePoints[byteNum][i] + p.X.SetByteSlice(serialized[offset:]) + offset += 32 + p.Y.SetByteSlice(serialized[offset:]) + offset += 32 + p.Z.SetInt(1) + } + } + data = &bytePoints + } + + // Return a closure that initializes the data on first access. This is done + // because the table takes a non-trivial amount of memory and initializing + // it unconditionally would cause anything that imports the package, either + // directly, or indirectly via transitive deps, to use that memory even if + // the caller never accesses any parts of the package that actually needs + // access to it. + var loadBytePointsOnce sync.Once + return func() *bytePointTable { + loadBytePointsOnce.Do(mustLoadBytePoints) + return data + } +}() diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go new file mode 100644 index 0000000000..225016d8de --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/modnscalar.go @@ -0,0 +1,1105 @@ +// Copyright (c) 2020-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "encoding/hex" + "math/big" +) + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone. +// http://cacr.uwaterloo.ca/hac/ + +// Many elliptic curve operations require working with scalars in a finite field +// characterized by the order of the group underlying the secp256k1 curve. +// Given this precision is larger than the biggest available native type, +// obviously some form of bignum math is needed. This code implements +// specialized fixed-precision field arithmetic rather than relying on an +// arbitrary-precision arithmetic package such as math/big for dealing with the +// math modulo the group order since the size is known. As a result, rather +// large performance gains are achieved by taking advantage of many +// optimizations not available to arbitrary-precision arithmetic and generic +// modular arithmetic algorithms. +// +// There are various ways to internally represent each element. For example, +// the most obvious representation would be to use an array of 4 uint64s (64 +// bits * 4 = 256 bits). However, that representation suffers from the fact +// that there is no native Go type large enough to handle the intermediate +// results while adding or multiplying two 64-bit numbers. +// +// Given the above, this implementation represents the field elements as 8 +// uint32s with each word (array entry) treated as base 2^32. This was chosen +// because most systems at the current time are 64-bit (or at least have 64-bit +// registers available for specialized purposes such as MMX) so the intermediate +// results can typically be done using a native register (and using uint64s to +// avoid the need for additional half-word arithmetic) + +const ( + // These fields provide convenient access to each of the words of the + // secp256k1 curve group order N to improve code readability. + // + // The group order of the curve per [SECG] is: + // 0xffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141 + // + // nolint: dupword + orderWordZero uint32 = 0xd0364141 + orderWordOne uint32 = 0xbfd25e8c + orderWordTwo uint32 = 0xaf48a03b + orderWordThree uint32 = 0xbaaedce6 + orderWordFour uint32 = 0xfffffffe + orderWordFive uint32 = 0xffffffff + orderWordSix uint32 = 0xffffffff + orderWordSeven uint32 = 0xffffffff + + // These fields provide convenient access to each of the words of the two's + // complement of the secp256k1 curve group order N to improve code + // readability. + // + // The two's complement of the group order is: + // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da173 2fc9bebf + orderComplementWordZero uint32 = (^orderWordZero) + 1 + orderComplementWordOne uint32 = ^orderWordOne + orderComplementWordTwo uint32 = ^orderWordTwo + orderComplementWordThree uint32 = ^orderWordThree + // orderComplementWordFour uint32 = ^orderWordFour // unused + // orderComplementWordFive uint32 = ^orderWordFive // unused + // orderComplementWordSix uint32 = ^orderWordSix // unused + // orderComplementWordSeven uint32 = ^orderWordSeven // unused + + // These fields provide convenient access to each of the words of the + // secp256k1 curve group order N / 2 to improve code readability and avoid + // the need to recalculate them. + // + // The half order of the secp256k1 curve group is: + // 0x7fffffff ffffffff ffffffff ffffffff 5d576e73 57a4501d dfe92f46 681b20a0 + // + // nolint: dupword + halfOrderWordZero uint32 = 0x681b20a0 + halfOrderWordOne uint32 = 0xdfe92f46 + halfOrderWordTwo uint32 = 0x57a4501d + halfOrderWordThree uint32 = 0x5d576e73 + halfOrderWordFour uint32 = 0xffffffff + halfOrderWordFive uint32 = 0xffffffff + halfOrderWordSix uint32 = 0xffffffff + halfOrderWordSeven uint32 = 0x7fffffff + + // uint32Mask is simply a mask with all bits set for a uint32 and is used to + // improve the readability of the code. + uint32Mask = 0xffffffff +) + +var ( + // zero32 is an array of 32 bytes used for the purposes of zeroing and is + // defined here to avoid extra allocations. + zero32 = [32]byte{} +) + +// ModNScalar implements optimized 256-bit constant-time fixed-precision +// arithmetic over the secp256k1 group order. This means all arithmetic is +// performed modulo: +// +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 +// +// It only implements the arithmetic needed for elliptic curve operations, +// however, the operations that are not implemented can typically be worked +// around if absolutely needed. For example, subtraction can be performed by +// adding the negation. +// +// Should it be absolutely necessary, conversion to the standard library +// math/big.Int can be accomplished by using the Bytes method, slicing the +// resulting fixed-size array, and feeding it to big.Int.SetBytes. However, +// that should typically be avoided when possible as conversion to big.Ints +// requires allocations, is not constant time, and is slower when working modulo +// the group order. +type ModNScalar struct { + // The scalar is represented as 8 32-bit integers in base 2^32. + // + // The following depicts the internal representation: + // --------------------------------------------------------- + // | n[7] | n[6] | ... | n[0] | + // | 32 bits | 32 bits | ... | 32 bits | + // | Mult: 2^(32*7) | Mult: 2^(32*6) | ... | Mult: 2^(32*0) | + // --------------------------------------------------------- + // + // For example, consider the number 2^87 + 2^42 + 1. It would be + // represented as: + // n[0] = 1 + // n[1] = 2^10 + // n[2] = 2^23 + // n[3..7] = 0 + // + // The full 256-bit value is then calculated by looping i from 7..0 and + // doing sum(n[i] * 2^(32i)) like so: + // n[7] * 2^(32*7) = 0 * 2^224 = 0 + // n[6] * 2^(32*6) = 0 * 2^192 = 0 + // ... + // n[2] * 2^(32*2) = 2^23 * 2^64 = 2^87 + // n[1] * 2^(32*1) = 2^10 * 2^32 = 2^42 + // n[0] * 2^(32*0) = 1 * 2^0 = 1 + // Sum: 0 + 0 + ... + 2^87 + 2^42 + 1 = 2^87 + 2^42 + 1 + n [8]uint32 +} + +// String returns the scalar as a human-readable hex string. +// +// This is NOT constant time. +func (s ModNScalar) String() string { + b := s.Bytes() + return hex.EncodeToString(b[:]) +} + +// Set sets the scalar equal to a copy of the passed one in constant time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s := new(ModNScalar).Set(s2).Add(1) so that s = s2 + 1 where s2 is not +// modified. +func (s *ModNScalar) Set(val *ModNScalar) *ModNScalar { + *s = *val + return s +} + +// Zero sets the scalar to zero in constant time. A newly created scalar is +// already set to zero. This function can be useful to clear an existing scalar +// for reuse. +func (s *ModNScalar) Zero() { + s.n[0] = 0 + s.n[1] = 0 + s.n[2] = 0 + s.n[3] = 0 + s.n[4] = 0 + s.n[5] = 0 + s.n[6] = 0 + s.n[7] = 0 +} + +// IsZeroBit returns 1 when the scalar is equal to zero or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsZero for the version that returns +// a bool. +func (s *ModNScalar) IsZeroBit() uint32 { + // The scalar can only be zero if no bits are set in any of the words. + bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7] + return constantTimeEq(bits, 0) +} + +// IsZero returns whether or not the scalar is equal to zero in constant time. +func (s *ModNScalar) IsZero() bool { + // The scalar can only be zero if no bits are set in any of the words. + bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7] + return bits == 0 +} + +// SetInt sets the scalar to the passed integer in constant time. This is a +// convenience function since it is fairly common to perform some arithmetic +// with small native integers. +// +// The scalar is returned to support chaining. This enables syntax like: +// s := new(ModNScalar).SetInt(2).Mul(s2) so that s = 2 * s2. +func (s *ModNScalar) SetInt(ui uint32) *ModNScalar { + s.Zero() + s.n[0] = ui + return s +} + +// constantTimeEq returns 1 if a == b or 0 otherwise in constant time. +func constantTimeEq(a, b uint32) uint32 { + return uint32((uint64(a^b) - 1) >> 63) +} + +// constantTimeNotEq returns 1 if a != b or 0 otherwise in constant time. +func constantTimeNotEq(a, b uint32) uint32 { + return ^uint32((uint64(a^b)-1)>>63) & 1 +} + +// constantTimeLess returns 1 if a < b or 0 otherwise in constant time. +func constantTimeLess(a, b uint32) uint32 { + return uint32((uint64(a) - uint64(b)) >> 63) +} + +// constantTimeLessOrEq returns 1 if a <= b or 0 otherwise in constant time. +func constantTimeLessOrEq(a, b uint32) uint32 { + return uint32((uint64(a) - uint64(b) - 1) >> 63) +} + +// constantTimeGreater returns 1 if a > b or 0 otherwise in constant time. +func constantTimeGreater(a, b uint32) uint32 { + return constantTimeLess(b, a) +} + +// constantTimeGreaterOrEq returns 1 if a >= b or 0 otherwise in constant time. +func constantTimeGreaterOrEq(a, b uint32) uint32 { + return constantTimeLessOrEq(b, a) +} + +// constantTimeMin returns min(a,b) in constant time. +func constantTimeMin(a, b uint32) uint32 { + return b ^ ((a ^ b) & -constantTimeLess(a, b)) +} + +// overflows determines if the current scalar is greater than or equal to the +// group order in constant time and returns 1 if it is or 0 otherwise. +func (s *ModNScalar) overflows() uint32 { + // The intuition here is that the scalar is greater than the group order if + // one of the higher individual words is greater than corresponding word of + // the group order and all higher words in the scalar are equal to their + // corresponding word of the group order. Since this type is modulo the + // group order, being equal is also an overflow back to 0. + // + // Note that the words 5, 6, and 7 are all the max uint32 value, so there is + // no need to test if those individual words of the scalar exceeds them, + // hence, only equality is checked for them. + highWordsEqual := constantTimeEq(s.n[7], orderWordSeven) + highWordsEqual &= constantTimeEq(s.n[6], orderWordSix) + highWordsEqual &= constantTimeEq(s.n[5], orderWordFive) + overflow := highWordsEqual & constantTimeGreater(s.n[4], orderWordFour) + highWordsEqual &= constantTimeEq(s.n[4], orderWordFour) + overflow |= highWordsEqual & constantTimeGreater(s.n[3], orderWordThree) + highWordsEqual &= constantTimeEq(s.n[3], orderWordThree) + overflow |= highWordsEqual & constantTimeGreater(s.n[2], orderWordTwo) + highWordsEqual &= constantTimeEq(s.n[2], orderWordTwo) + overflow |= highWordsEqual & constantTimeGreater(s.n[1], orderWordOne) + highWordsEqual &= constantTimeEq(s.n[1], orderWordOne) + overflow |= highWordsEqual & constantTimeGreaterOrEq(s.n[0], orderWordZero) + + return overflow +} + +// reduce256 reduces the current scalar modulo the group order in accordance +// with the overflows parameter in constant time. The overflows parameter +// specifies whether or not the scalar is known to be greater than the group +// order and MUST either be 1 in the case it is or 0 in the case it is not for a +// correct result. +func (s *ModNScalar) reduce256(overflows uint32) { + // Notice that since s < 2^256 < 2N (where N is the group order), the max + // possible number of reductions required is one. Therefore, in the case a + // reduction is needed, it can be performed with a single subtraction of N. + // Also, recall that subtraction is equivalent to addition by the two's + // complement while ignoring the carry. + // + // When s >= N, the overflows parameter will be 1. Conversely, it will be 0 + // when s < N. Thus multiplying by the overflows parameter will either + // result in 0 or the multiplicand itself. + // + // Combining the above along with the fact that s + 0 = s, the following is + // a constant time implementation that works by either adding 0 or the two's + // complement of N as needed. + // + // The final result will be in the range 0 <= s < N as expected. + overflows64 := uint64(overflows) + c := uint64(s.n[0]) + overflows64*uint64(orderComplementWordZero) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[1]) + overflows64*uint64(orderComplementWordOne) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[2]) + overflows64*uint64(orderComplementWordTwo) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[3]) + overflows64*uint64(orderComplementWordThree) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[4]) + overflows64 // * 1 + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[5]) // + overflows64 * 0 + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[6]) // + overflows64 * 0 + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[7]) // + overflows64 * 0 + s.n[7] = uint32(c & uint32Mask) +} + +// SetBytes interprets the provided array as a 256-bit big-endian unsigned +// integer, reduces it modulo the group order, sets the scalar to the result, +// and returns either 1 if it was reduced (aka it overflowed) or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +func (s *ModNScalar) SetBytes(b *[32]byte) uint32 { + // Pack the 256 total bits across the 8 uint32 words. This could be done + // with a for loop, but benchmarks show this unrolled version is about 2 + // times faster than the variant that uses a loop. + s.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | uint32(b[28])<<24 + s.n[1] = uint32(b[27]) | uint32(b[26])<<8 | uint32(b[25])<<16 | uint32(b[24])<<24 + s.n[2] = uint32(b[23]) | uint32(b[22])<<8 | uint32(b[21])<<16 | uint32(b[20])<<24 + s.n[3] = uint32(b[19]) | uint32(b[18])<<8 | uint32(b[17])<<16 | uint32(b[16])<<24 + s.n[4] = uint32(b[15]) | uint32(b[14])<<8 | uint32(b[13])<<16 | uint32(b[12])<<24 + s.n[5] = uint32(b[11]) | uint32(b[10])<<8 | uint32(b[9])<<16 | uint32(b[8])<<24 + s.n[6] = uint32(b[7]) | uint32(b[6])<<8 | uint32(b[5])<<16 | uint32(b[4])<<24 + s.n[7] = uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + + // The value might be >= N, so reduce it as required and return whether or + // not it was reduced. + needsReduce := s.overflows() + s.reduce256(needsReduce) + return needsReduce +} + +// zeroArray32 zeroes the provided 32-byte buffer. +func zeroArray32(b *[32]byte) { + copy(b[:], zero32[:]) +} + +// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned +// integer (meaning it is truncated to the first 32 bytes), reduces it modulo +// the group order, sets the scalar to the result, and returns whether or not +// the resulting truncated 256-bit integer overflowed in constant time. +// +// Note that since passing a slice with more than 32 bytes is truncated, it is +// possible that the truncated value is less than the order of the curve and +// hence it will not be reported as having overflowed in that case. It is up to +// the caller to decide whether it needs to provide numbers of the appropriate +// size or it is acceptable to use this function with the described truncation +// and overflow behavior. +func (s *ModNScalar) SetByteSlice(b []byte) bool { + var b32 [32]byte + b = b[:constantTimeMin(uint32(len(b)), 32)] + copy(b32[:], b32[:32-len(b)]) + copy(b32[32-len(b):], b) + result := s.SetBytes(&b32) + zeroArray32(&b32) + return result != 0 +} + +// PutBytesUnchecked unpacks the scalar to a 32-byte big-endian value directly +// into the passed byte slice in constant time. The target slice must have at +// least 32 bytes available or it will panic. +// +// There is a similar function, PutBytes, which unpacks the scalar into a +// 32-byte array directly. This version is provided since it can be useful to +// write directly into part of a larger buffer without needing a separate +// allocation. +// +// Preconditions: +// - The target slice MUST have at least 32 bytes available +func (s *ModNScalar) PutBytesUnchecked(b []byte) { + // Unpack the 256 total bits from the 8 uint32 words. This could be done + // with a for loop, but benchmarks show this unrolled version is about 2 + // times faster than the variant which uses a loop. + b[31] = byte(s.n[0]) + b[30] = byte(s.n[0] >> 8) + b[29] = byte(s.n[0] >> 16) + b[28] = byte(s.n[0] >> 24) + b[27] = byte(s.n[1]) + b[26] = byte(s.n[1] >> 8) + b[25] = byte(s.n[1] >> 16) + b[24] = byte(s.n[1] >> 24) + b[23] = byte(s.n[2]) + b[22] = byte(s.n[2] >> 8) + b[21] = byte(s.n[2] >> 16) + b[20] = byte(s.n[2] >> 24) + b[19] = byte(s.n[3]) + b[18] = byte(s.n[3] >> 8) + b[17] = byte(s.n[3] >> 16) + b[16] = byte(s.n[3] >> 24) + b[15] = byte(s.n[4]) + b[14] = byte(s.n[4] >> 8) + b[13] = byte(s.n[4] >> 16) + b[12] = byte(s.n[4] >> 24) + b[11] = byte(s.n[5]) + b[10] = byte(s.n[5] >> 8) + b[9] = byte(s.n[5] >> 16) + b[8] = byte(s.n[5] >> 24) + b[7] = byte(s.n[6]) + b[6] = byte(s.n[6] >> 8) + b[5] = byte(s.n[6] >> 16) + b[4] = byte(s.n[6] >> 24) + b[3] = byte(s.n[7]) + b[2] = byte(s.n[7] >> 8) + b[1] = byte(s.n[7] >> 16) + b[0] = byte(s.n[7] >> 24) +} + +// PutBytes unpacks the scalar to a 32-byte big-endian value using the passed +// byte array in constant time. +// +// There is a similar function, PutBytesUnchecked, which unpacks the scalar into +// a slice that must have at least 32 bytes available. This version is provided +// since it can be useful to write directly into an array that is type checked. +// +// Alternatively, there is also Bytes, which unpacks the scalar into a new array +// and returns that which can sometimes be more ergonomic in applications that +// aren't concerned about an additional copy. +func (s *ModNScalar) PutBytes(b *[32]byte) { + s.PutBytesUnchecked(b[:]) +} + +// Bytes unpacks the scalar to a 32-byte big-endian value in constant time. +// +// See PutBytes and PutBytesUnchecked for variants that allow an array or slice +// to be passed which can be useful to cut down on the number of allocations +// by allowing the caller to reuse a buffer or write directly into part of a +// larger buffer. +func (s *ModNScalar) Bytes() [32]byte { + var b [32]byte + s.PutBytesUnchecked(b[:]) + return b +} + +// IsOdd returns whether or not the scalar is an odd number in constant time. +func (s *ModNScalar) IsOdd() bool { + // Only odd numbers have the bottom bit set. + return s.n[0]&1 == 1 +} + +// Equals returns whether or not the two scalars are the same in constant time. +func (s *ModNScalar) Equals(val *ModNScalar) bool { + // Xor only sets bits when they are different, so the two scalars can only + // be the same if no bits are set after xoring each word. + bits := (s.n[0] ^ val.n[0]) | (s.n[1] ^ val.n[1]) | (s.n[2] ^ val.n[2]) | + (s.n[3] ^ val.n[3]) | (s.n[4] ^ val.n[4]) | (s.n[5] ^ val.n[5]) | + (s.n[6] ^ val.n[6]) | (s.n[7] ^ val.n[7]) + + return bits == 0 +} + +// Add2 adds the passed two scalars together modulo the group order in constant +// time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.Add2(s, s2).AddInt(1) so that s3 = s + s2 + 1. +func (s *ModNScalar) Add2(val1, val2 *ModNScalar) *ModNScalar { + c := uint64(val1.n[0]) + uint64(val2.n[0]) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[1]) + uint64(val2.n[1]) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[2]) + uint64(val2.n[2]) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[3]) + uint64(val2.n[3]) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[4]) + uint64(val2.n[4]) + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[5]) + uint64(val2.n[5]) + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[6]) + uint64(val2.n[6]) + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[7]) + uint64(val2.n[7]) + s.n[7] = uint32(c & uint32Mask) + + // The result is now 256 bits, but it might still be >= N, so use the + // existing normal reduce method for 256-bit values. + s.reduce256(uint32(c>>32) + s.overflows()) + return s +} + +// Add adds the passed scalar to the existing one modulo the group order in +// constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Add(s2).AddInt(1) so that s = s + s2 + 1. +func (s *ModNScalar) Add(val *ModNScalar) *ModNScalar { + return s.Add2(s, val) +} + +// accumulator96 provides a 96-bit accumulator for use in the intermediate +// calculations requiring more than 64-bits. +type accumulator96 struct { + n [3]uint32 +} + +// Add adds the passed unsigned 64-bit value to the accumulator. +func (a *accumulator96) Add(v uint64) { + low := uint32(v & uint32Mask) + hi := uint32(v >> 32) + a.n[0] += low + hi += constantTimeLess(a.n[0], low) // Carry if overflow in n[0]. + a.n[1] += hi + a.n[2] += constantTimeLess(a.n[1], hi) // Carry if overflow in n[1]. +} + +// Rsh32 right shifts the accumulator by 32 bits. +func (a *accumulator96) Rsh32() { + a.n[0] = a.n[1] + a.n[1] = a.n[2] + a.n[2] = 0 +} + +// reduce385 reduces the 385-bit intermediate result in the passed terms modulo +// the group order in constant time and stores the result in s. +func (s *ModNScalar) reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12 uint64) { + // At this point, the intermediate result in the passed terms has been + // reduced to fit within 385 bits, so reduce it again using the same method + // described in reduce512. As before, the intermediate result will end up + // being reduced by another 127 bits to 258 bits, thus 9 32-bit terms are + // needed for this iteration. The reduced terms are assigned back to t0 + // through t8. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead until the value is reduced enough to use native uint64s. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0. + acc.Add(t8 * uint64(orderComplementWordZero)) + t0 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(t1) + acc.Add(t8 * uint64(orderComplementWordOne)) + acc.Add(t9 * uint64(orderComplementWordZero)) + t1 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(t2) + acc.Add(t8 * uint64(orderComplementWordTwo)) + acc.Add(t9 * uint64(orderComplementWordOne)) + acc.Add(t10 * uint64(orderComplementWordZero)) + t2 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(t3) + acc.Add(t8 * uint64(orderComplementWordThree)) + acc.Add(t9 * uint64(orderComplementWordTwo)) + acc.Add(t10 * uint64(orderComplementWordOne)) + acc.Add(t11 * uint64(orderComplementWordZero)) + t3 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(t4) + acc.Add(t8) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t9 * uint64(orderComplementWordThree)) + acc.Add(t10 * uint64(orderComplementWordTwo)) + acc.Add(t11 * uint64(orderComplementWordOne)) + acc.Add(t12 * uint64(orderComplementWordZero)) + t4 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(t5) + // acc.Add(t8 * uint64(orderComplementWordFive)) // 0 + acc.Add(t9) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t10 * uint64(orderComplementWordThree)) + acc.Add(t11 * uint64(orderComplementWordTwo)) + acc.Add(t12 * uint64(orderComplementWordOne)) + t5 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(t6) + // acc.Add(t8 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t9 * uint64(orderComplementWordFive)) // 0 + acc.Add(t10) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t11 * uint64(orderComplementWordThree)) + acc.Add(t12 * uint64(orderComplementWordTwo)) + t6 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(t7) + // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t9 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t10 * uint64(orderComplementWordFive)) // 0 + acc.Add(t11) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t12 * uint64(orderComplementWordThree)) + t7 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t10 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t11 * uint64(orderComplementWordFive)) // 0 + acc.Add(t12) // * uint64(orderComplementWordFour) // * 1 + t8 = uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // NOTE: All of the remaining multiplications for this iteration result in 0 + // as they all involve multiplying by combinations of the fifth, sixth, and + // seventh words of the two's complement of N, which are 0, so skip them. + + // At this point, the result is reduced to fit within 258 bits, so reduce it + // again using a slightly modified version of the same method. The maximum + // value in t8 is 2 at this point and therefore multiplying it by each word + // of the two's complement of N and adding it to a 32-bit term will result + // in a maximum requirement of 33 bits, so it is safe to use native uint64s + // here for the intermediate term carry propagation. + // + // Also, since the maximum value in t8 is 2, this ends up reducing by + // another 2 bits to 256 bits. + c := t0 + t8*uint64(orderComplementWordZero) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + t1 + t8*uint64(orderComplementWordOne) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + t2 + t8*uint64(orderComplementWordTwo) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + t3 + t8*uint64(orderComplementWordThree) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + t4 + t8 // * uint64(orderComplementWordFour) == * 1 + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + t5 // + t8*uint64(orderComplementWordFive) == 0 + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + t6 // + t8*uint64(orderComplementWordSix) == 0 + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + t7 // + t8*uint64(orderComplementWordSeven) == 0 + s.n[7] = uint32(c & uint32Mask) + + // The result is now 256 bits, but it might still be >= N, so use the + // existing normal reduce method for 256-bit values. + s.reduce256(uint32(c>>32) + s.overflows()) +} + +// reduce512 reduces the 512-bit intermediate result in the passed terms modulo +// the group order down to 385 bits in constant time and stores the result in s. +func (s *ModNScalar) reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15 uint64) { + // At this point, the intermediate result in the passed terms is grouped + // into the respective bases. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, where log_2(c) < t, + // highly efficient reduction can be achieved per the provided algorithm. + // + // The secp256k1 group order fits this criteria since it is: + // 2^256 - 432420386565659656852420866394968145599 + // + // Technically the max possible value here is (N-1)^2 since the two scalars + // being multiplied are always mod N. Nevertheless, it is safer to consider + // it to be (2^256-1)^2 = 2^512 - 2^257 + 1 since it is the product of two + // 256-bit values. + // + // The algorithm is to reduce the result modulo the prime by subtracting + // multiples of the group order N. However, in order simplify carry + // propagation, this adds with the two's complement of N to achieve the same + // result. + // + // Since the two's complement of N has 127 leading zero bits, this will end + // up reducing the intermediate result from 512 bits to 385 bits, resulting + // in 13 32-bit terms. The reduced terms are assigned back to t0 through + // t12. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0. + acc.Add(t8 * uint64(orderComplementWordZero)) + t0 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(t1) + acc.Add(t8 * uint64(orderComplementWordOne)) + acc.Add(t9 * uint64(orderComplementWordZero)) + t1 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(t2) + acc.Add(t8 * uint64(orderComplementWordTwo)) + acc.Add(t9 * uint64(orderComplementWordOne)) + acc.Add(t10 * uint64(orderComplementWordZero)) + t2 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(t3) + acc.Add(t8 * uint64(orderComplementWordThree)) + acc.Add(t9 * uint64(orderComplementWordTwo)) + acc.Add(t10 * uint64(orderComplementWordOne)) + acc.Add(t11 * uint64(orderComplementWordZero)) + t3 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(t4) + acc.Add(t8) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t9 * uint64(orderComplementWordThree)) + acc.Add(t10 * uint64(orderComplementWordTwo)) + acc.Add(t11 * uint64(orderComplementWordOne)) + acc.Add(t12 * uint64(orderComplementWordZero)) + t4 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(t5) + // acc.Add(t8 * uint64(orderComplementWordFive)) // 0 + acc.Add(t9) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t10 * uint64(orderComplementWordThree)) + acc.Add(t11 * uint64(orderComplementWordTwo)) + acc.Add(t12 * uint64(orderComplementWordOne)) + acc.Add(t13 * uint64(orderComplementWordZero)) + t5 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(t6) + // acc.Add(t8 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t9 * uint64(orderComplementWordFive)) // 0 + acc.Add(t10) // * uint64(orderComplementWordFour)) // * 1 + acc.Add(t11 * uint64(orderComplementWordThree)) + acc.Add(t12 * uint64(orderComplementWordTwo)) + acc.Add(t13 * uint64(orderComplementWordOne)) + acc.Add(t14 * uint64(orderComplementWordZero)) + t6 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(t7) + // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t9 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t10 * uint64(orderComplementWordFive)) // 0 + acc.Add(t11) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t12 * uint64(orderComplementWordThree)) + acc.Add(t13 * uint64(orderComplementWordTwo)) + acc.Add(t14 * uint64(orderComplementWordOne)) + acc.Add(t15 * uint64(orderComplementWordZero)) + t7 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t10 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t11 * uint64(orderComplementWordFive)) // 0 + acc.Add(t12) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t13 * uint64(orderComplementWordThree)) + acc.Add(t14 * uint64(orderComplementWordTwo)) + acc.Add(t15 * uint64(orderComplementWordOne)) + t8 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*9). + // acc.Add(t10 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t11 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t12 * uint64(orderComplementWordFive)) // 0 + acc.Add(t13) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t14 * uint64(orderComplementWordThree)) + acc.Add(t15 * uint64(orderComplementWordTwo)) + t9 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*10). + // acc.Add(t11 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t12 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t13 * uint64(orderComplementWordFive)) // 0 + acc.Add(t14) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t15 * uint64(orderComplementWordThree)) + t10 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*11). + // acc.Add(t12 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t13 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t14 * uint64(orderComplementWordFive)) // 0 + acc.Add(t15) // * uint64(orderComplementWordFour) // * 1 + t11 = uint64(acc.n[0]) + acc.Rsh32() + + // NOTE: All of the remaining multiplications for this iteration result in 0 + // as they all involve multiplying by combinations of the fifth, sixth, and + // seventh words of the two's complement of N, which are 0, so skip them. + + // Terms for 2^(32*12). + t12 = uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // At this point, the result is reduced to fit within 385 bits, so reduce it + // again using the same method accordingly. + s.reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) +} + +// Mul2 multiplies the passed two scalars together modulo the group order in +// constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.Mul2(s, s2).AddInt(1) so that s3 = (s * s2) + 1. +func (s *ModNScalar) Mul2(val, val2 *ModNScalar) *ModNScalar { + // This could be done with for loops and an array to store the intermediate + // terms, but this unrolled version is significantly faster. + + // The overall strategy employed here is: + // 1) Calculate the 512-bit product of the two scalars using the standard + // pencil-and-paper method. + // 2) Reduce the result modulo the prime by effectively subtracting + // multiples of the group order N (actually performed by adding multiples + // of the two's complement of N to avoid implementing subtraction). + // 3) Repeat step 2 noting that each iteration reduces the required number + // of bits by 127 because the two's complement of N has 127 leading zero + // bits. + // 4) Once reduced to 256 bits, call the existing reduce method to perform + // a final reduction as needed. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.Add(uint64(val.n[0]) * uint64(val2.n[0])) + t0 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(uint64(val.n[0]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[0])) + t1 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(uint64(val.n[0]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[0])) + t2 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(uint64(val.n[0]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[0])) + t3 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(uint64(val.n[0]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[0])) + t4 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(uint64(val.n[0]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[0])) + t5 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(uint64(val.n[0]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[0])) + t6 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(uint64(val.n[0]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[0])) + t7 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + acc.Add(uint64(val.n[1]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[1])) + t8 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*9). + acc.Add(uint64(val.n[2]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[2])) + t9 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*10). + acc.Add(uint64(val.n[3]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[3])) + t10 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*11). + acc.Add(uint64(val.n[4]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[4])) + t11 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*12). + acc.Add(uint64(val.n[5]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[5])) + t12 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*13). + acc.Add(uint64(val.n[6]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[6])) + t13 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*14). + acc.Add(uint64(val.n[7]) * uint64(val2.n[7])) + t14 := uint64(acc.n[0]) + acc.Rsh32() + + // What's left is for 2^(32*15). + t15 := uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // At this point, all of the terms are grouped into their respective base + // and occupy up to 512 bits. Reduce the result accordingly. + s.reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15) + return s +} + +// Mul multiplies the passed scalar with the existing one modulo the group order +// in constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Mul(s2).AddInt(1) so that s = (s * s2) + 1. +func (s *ModNScalar) Mul(val *ModNScalar) *ModNScalar { + return s.Mul2(s, val) +} + +// SquareVal squares the passed scalar modulo the group order in constant time +// and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.SquareVal(s).Mul(s) so that s3 = s^2 * s = s^3. +func (s *ModNScalar) SquareVal(val *ModNScalar) *ModNScalar { + // This could technically be optimized slightly to take advantage of the + // fact that many of the intermediate calculations in squaring are just + // doubling, however, benchmarking has shown that due to the need to use a + // 96-bit accumulator, any savings are essentially offset by that and + // consequently there is no real difference in performance over just + // multiplying the value by itself to justify the extra code for now. This + // can be revisited in the future if it becomes a bottleneck in practice. + + return s.Mul2(val, val) +} + +// Square squares the scalar modulo the group order in constant time. The +// existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Square().Mul(s2) so that s = s^2 * s2. +func (s *ModNScalar) Square() *ModNScalar { + return s.SquareVal(s) +} + +// NegateVal negates the passed scalar modulo the group order and stores the +// result in s in constant time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.NegateVal(s2).AddInt(1) so that s = -s2 + 1. +func (s *ModNScalar) NegateVal(val *ModNScalar) *ModNScalar { + // Since the scalar is already in the range 0 <= val < N, where N is the + // group order, negation modulo the group order is just the group order + // minus the value. This implies that the result will always be in the + // desired range with the sole exception of 0 because N - 0 = N itself. + // + // Therefore, in order to avoid the need to reduce the result for every + // other case in order to achieve constant time, this creates a mask that is + // all 0s in the case of the scalar being negated is 0 and all 1s otherwise + // and bitwise ands that mask with each word. + // + // Finally, to simplify the carry propagation, this adds the two's + // complement of the scalar to N in order to achieve the same result. + bits := val.n[0] | val.n[1] | val.n[2] | val.n[3] | val.n[4] | val.n[5] | + val.n[6] | val.n[7] + mask := uint64(uint32Mask * constantTimeNotEq(bits, 0)) + c := uint64(orderWordZero) + (uint64(^val.n[0]) + 1) + s.n[0] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordOne) + uint64(^val.n[1]) + s.n[1] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordTwo) + uint64(^val.n[2]) + s.n[2] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordThree) + uint64(^val.n[3]) + s.n[3] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordFour) + uint64(^val.n[4]) + s.n[4] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordFive) + uint64(^val.n[5]) + s.n[5] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordSix) + uint64(^val.n[6]) + s.n[6] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordSeven) + uint64(^val.n[7]) + s.n[7] = uint32(c & mask) + return s +} + +// Negate negates the scalar modulo the group order in constant time. The +// existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Negate().AddInt(1) so that s = -s + 1. +func (s *ModNScalar) Negate() *ModNScalar { + return s.NegateVal(s) +} + +// InverseValNonConst finds the modular multiplicative inverse of the passed +// scalar and stores result in s in *non-constant* time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.InverseVal(s1).Mul(s2) so that s3 = s1^-1 * s2. +func (s *ModNScalar) InverseValNonConst(val *ModNScalar) *ModNScalar { + // This is making use of big integers for now. Ideally it will be replaced + // with an implementation that does not depend on big integers. + valBytes := val.Bytes() + bigVal := new(big.Int).SetBytes(valBytes[:]) + bigVal.ModInverse(bigVal, curveParams.N) + s.SetByteSlice(bigVal.Bytes()) + return s +} + +// InverseNonConst finds the modular multiplicative inverse of the scalar in +// *non-constant* time. The existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Inverse().Mul(s2) so that s = s^-1 * s2. +func (s *ModNScalar) InverseNonConst() *ModNScalar { + return s.InverseValNonConst(s) +} + +// IsOverHalfOrder returns whether or not the scalar exceeds the group order +// divided by 2 in constant time. +func (s *ModNScalar) IsOverHalfOrder() bool { + // The intuition here is that the scalar is greater than half of the group + // order if one of the higher individual words is greater than the + // corresponding word of the half group order and all higher words in the + // scalar are equal to their corresponding word of the half group order. + // + // Note that the words 4, 5, and 6 are all the max uint32 value, so there is + // no need to test if those individual words of the scalar exceeds them, + // hence, only equality is checked for them. + result := constantTimeGreater(s.n[7], halfOrderWordSeven) + highWordsEqual := constantTimeEq(s.n[7], halfOrderWordSeven) + highWordsEqual &= constantTimeEq(s.n[6], halfOrderWordSix) + highWordsEqual &= constantTimeEq(s.n[5], halfOrderWordFive) + highWordsEqual &= constantTimeEq(s.n[4], halfOrderWordFour) + result |= highWordsEqual & constantTimeGreater(s.n[3], halfOrderWordThree) + highWordsEqual &= constantTimeEq(s.n[3], halfOrderWordThree) + result |= highWordsEqual & constantTimeGreater(s.n[2], halfOrderWordTwo) + highWordsEqual &= constantTimeEq(s.n[2], halfOrderWordTwo) + result |= highWordsEqual & constantTimeGreater(s.n[1], halfOrderWordOne) + highWordsEqual &= constantTimeEq(s.n[1], halfOrderWordOne) + result |= highWordsEqual & constantTimeGreater(s.n[0], halfOrderWordZero) + + return result != 0 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go new file mode 100644 index 0000000000..70a75bb81c --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/nonce.go @@ -0,0 +1,263 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "bytes" + "crypto/sha256" + "hash" +) + +// References: +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) +// +// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules: +// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules +// (CER) and Distinguished Encoding Rules (DER) +// +// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0) +// https://www.secg.org/sec1-v2.pdf + +var ( + // singleZero is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleZero = []byte{0x00} + + // zeroInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize) + + // singleOne is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleOne = []byte{0x01} + + // oneInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size) +) + +// hmacsha256 implements a resettable version of HMAC-SHA256. +type hmacsha256 struct { + inner, outer hash.Hash + ipad, opad [sha256.BlockSize]byte +} + +// Write adds data to the running hash. +func (h *hmacsha256) Write(p []byte) { + h.inner.Write(p) +} + +// initKey initializes the HMAC-SHA256 instance to the provided key. +func (h *hmacsha256) initKey(key []byte) { + // Hash the key if it is too large. + if len(key) > sha256.BlockSize { + h.outer.Write(key) + key = h.outer.Sum(nil) + } + copy(h.ipad[:], key) + copy(h.opad[:], key) + for i := range h.ipad { + h.ipad[i] ^= 0x36 + } + for i := range h.opad { + h.opad[i] ^= 0x5c + } + h.inner.Write(h.ipad[:]) +} + +// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it +// with the provided key. It is equivalent to creating a new instance with the +// provided key without allocating more memory. +func (h *hmacsha256) ResetKey(key []byte) { + h.inner.Reset() + h.outer.Reset() + copy(h.ipad[:], zeroInitializer) + copy(h.opad[:], zeroInitializer) + h.initKey(key) +} + +// Resets the HMAC-SHA256 to its initial state using the current key. +func (h *hmacsha256) Reset() { + h.inner.Reset() + h.inner.Write(h.ipad[:]) +} + +// Sum returns the hash of the written data. +func (h *hmacsha256) Sum() []byte { + h.outer.Reset() + h.outer.Write(h.opad[:]) + h.outer.Write(h.inner.Sum(nil)) + return h.outer.Sum(nil) +} + +// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key. +func newHMACSHA256(key []byte) *hmacsha256 { + h := new(hmacsha256) + h.inner = sha256.New() + h.outer = sha256.New() + h.initKey(key) + return h +} + +// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using +// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input +// and returns a 32-byte nonce to be used for deterministic signing. The extra +// and version arguments are optional, but allow additional data to be added to +// the input of the HMAC. When provided, the extra data must be 32-bytes and +// version must be 16 bytes or they will be ignored. +// +// Finally, the extraIterations parameter provides a method to produce a stream +// of deterministic nonces to ensure the signing code is able to produce a nonce +// that results in a valid signature in the extremely unlikely event the +// original nonce produced results in an invalid signature (e.g. R == 0). +// Signing code should start with 0 and increment it if necessary. +func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar { + // Input to HMAC is the 32-byte private key and the 32-byte hash. In + // addition, it may include the optional 32-byte extra data and 16-byte + // version. Create a fixed-size array to avoid extra allocs and slice it + // properly. + const ( + privKeyLen = 32 + hashLen = 32 + extraLen = 32 + versionLen = 16 + ) + var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte + + // Truncate rightmost bytes of private key and hash if they are too long and + // leave left padding of zeros when they're too short. + if len(privKey) > privKeyLen { + privKey = privKey[:privKeyLen] + } + if len(hash) > hashLen { + hash = hash[:hashLen] + } + offset := privKeyLen - len(privKey) // Zero left padding if needed. + offset += copy(keyBuf[offset:], privKey) + offset += hashLen - len(hash) // Zero left padding if needed. + offset += copy(keyBuf[offset:], hash) + if len(extra) == extraLen { + offset += copy(keyBuf[offset:], extra) + if len(version) == versionLen { + offset += copy(keyBuf[offset:], version) + } + } else if len(version) == versionLen { + // When the version was specified, but not the extra data, leave the + // extra data portion all zero. + offset += privKeyLen + offset += copy(keyBuf[offset:], version) + } + key := keyBuf[:offset] + + // Step B. + // + // V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is + // equal to 8*ceil(hashLen/8). + // + // Note that since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. Also, since it isn't modified, + // start with a global value. + v := oneInitializer + + // Step C (Go zeroes all allocated memory). + // + // K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is + // equal to 8*ceil(hashLen/8). + // + // As above, since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. + k := zeroInitializer[:hashLen] + + // Step D. + // + // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher := newHMACSHA256(k) + hasher.Write(oneInitializer) + hasher.Write(singleZero) + hasher.Write(key) + k = hasher.Sum() + + // Step E. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step F. + // + // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher.Reset() + hasher.Write(v) + hasher.Write(singleOne) + hasher.Write(key) + k = hasher.Sum() + + // Step G. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step H. + // + // Repeat until the value is nonzero and less than the curve order. + var generated uint32 + for { + // Step H1 and H2. + // + // Set T to the empty sequence. The length of T (in bits) is denoted + // tlen; thus, at that point, tlen = 0. + // + // While tlen < qlen, do the following: + // V = HMAC_K(V) + // T = T || V + // + // Note that because the hash function output is the same length as the + // private key in this optimized implementation, there is no need to + // loop or create an intermediate T. + hasher.Reset() + hasher.Write(v) + v = hasher.Sum() + + // Step H3. + // + // k = bits2int(T) + // If k is within the range [1,q-1], return it. + // + // Otherwise, compute: + // K = HMAC_K(V || 0x00) + // V = HMAC_K(V) + var secret ModNScalar + overflow := secret.SetByteSlice(v) + if !overflow && !secret.IsZero() { + generated++ + if generated > extraIterations { + return &secret + } + } + + // K = HMAC_K(V || 0x00) + hasher.Reset() + hasher.Write(v) + hasher.Write(singleZero) + k = hasher.Sum() + + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + } +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go new file mode 100644 index 0000000000..e6b7be3506 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey.go @@ -0,0 +1,111 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + cryptorand "crypto/rand" + "io" +) + +// PrivateKey provides facilities for working with secp256k1 private keys within +// this package and includes functionality such as serializing and parsing them +// as well as computing their associated public key. +type PrivateKey struct { + Key ModNScalar +} + +// NewPrivateKey instantiates a new private key from a scalar encoded as a +// big integer. +func NewPrivateKey(key *ModNScalar) *PrivateKey { + return &PrivateKey{Key: *key} +} + +// PrivKeyFromBytes returns a private based on the provided byte slice which is +// interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1], +// where N is the order of the curve. +// +// WARNING: This means passing a slice with more than 32 bytes is truncated and +// that truncated value is reduced modulo N. Further, 0 is not a valid private +// key. It is up to the caller to provide a value in the appropriate range of +// [1, N-1]. Failure to do so will either result in an invalid private key or +// potentially weak private keys that have bias that could be exploited. +// +// This function primarily exists to provide a mechanism for converting +// serialized private keys that are already known to be good. +// +// Typically callers should make use of GeneratePrivateKey or +// GeneratePrivateKeyFromRand when creating private keys since they properly +// handle generation of appropriate values. +func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey { + var privKey PrivateKey + privKey.Key.SetByteSlice(privKeyBytes) + return &privKey +} + +// generatePrivateKey generates and returns a new private key that is suitable +// for use with secp256k1 using the provided reader as a source of entropy. The +// provided reader must be a source of cryptographically secure randomness to +// avoid weak private keys. +func generatePrivateKey(rand io.Reader) (*PrivateKey, error) { + // The group order is close enough to 2^256 that there is only roughly a 1 + // in 2^128 chance of generating an invalid private key, so this loop will + // virtually never run more than a single iteration in practice. + var key PrivateKey + var b32 [32]byte + for valid := false; !valid; { + if _, err := io.ReadFull(rand, b32[:]); err != nil { + return nil, err + } + + // The private key is only valid when it is in the range [1, N-1], where + // N is the order of the curve. + overflow := key.Key.SetBytes(&b32) + valid = (key.Key.IsZeroBit() | overflow) == 0 + } + zeroArray32(&b32) + + return &key, nil +} + +// GeneratePrivateKey generates and returns a new cryptographically secure +// private key that is suitable for use with secp256k1. +func GeneratePrivateKey() (*PrivateKey, error) { + return generatePrivateKey(cryptorand.Reader) +} + +// GeneratePrivateKeyFromRand generates a private key that is suitable for use +// with secp256k1 using the provided reader as a source of entropy. The +// provided reader must be a source of cryptographically secure randomness, such +// as [crypto/rand.Reader], to avoid weak private keys. +func GeneratePrivateKeyFromRand(rand io.Reader) (*PrivateKey, error) { + return generatePrivateKey(rand) +} + +// PubKey computes and returns the public key corresponding to this private key. +func (p *PrivateKey) PubKey() *PublicKey { + var result JacobianPoint + ScalarBaseMultNonConst(&p.Key, &result) + result.ToAffine() + return NewPublicKey(&result.X, &result.Y) +} + +// Zero manually clears the memory associated with the private key. This can be +// used to explicitly clear key material from memory for enhanced security +// against memory scraping. +func (p *PrivateKey) Zero() { + p.Key.Zero() +} + +// PrivKeyBytesLen defines the length in bytes of a serialized private key. +const PrivKeyBytesLen = 32 + +// Serialize returns the private key as a 256-bit big-endian binary-encoded +// number, padded to a length of 32 bytes. +func (p PrivateKey) Serialize() []byte { + var privKeyBytes [PrivKeyBytesLen]byte + p.Key.PutBytes(&privKeyBytes) + return privKeyBytes[:] +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go new file mode 100644 index 0000000000..2f8815bedf --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/pubkey.go @@ -0,0 +1,236 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [SEC1] Elliptic Curve Cryptography +// https://www.secg.org/sec1-v2.pdf +// +// [SEC2] Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [ANSI X9.62-1998] Public Key Cryptography For The Financial Services +// Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA) + +import ( + "fmt" +) + +const ( + // PubKeyBytesLenCompressed is the number of bytes of a serialized + // compressed public key. + PubKeyBytesLenCompressed = 33 + + // PubKeyBytesLenUncompressed is the number of bytes of a serialized + // uncompressed public key. + PubKeyBytesLenUncompressed = 65 + + // PubKeyFormatCompressedEven is the identifier prefix byte for a public key + // whose Y coordinate is even when serialized in the compressed format per + // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4). + PubKeyFormatCompressedEven byte = 0x02 + + // PubKeyFormatCompressedOdd is the identifier prefix byte for a public key + // whose Y coordinate is odd when serialized in the compressed format per + // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4). + PubKeyFormatCompressedOdd byte = 0x03 + + // PubKeyFormatUncompressed is the identifier prefix byte for a public key + // when serialized according in the uncompressed format per section 2.3.3 of + // [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.3). + PubKeyFormatUncompressed byte = 0x04 + + // PubKeyFormatHybridEven is the identifier prefix byte for a public key + // whose Y coordinate is even when serialized according to the hybrid format + // per section 4.3.6 of [ANSI X9.62-1998]. + // + // NOTE: This format makes little sense in practice an therefore this + // package will not produce public keys serialized in this format. However, + // it will parse them since they exist in the wild. + PubKeyFormatHybridEven byte = 0x06 + + // PubKeyFormatHybridOdd is the identifier prefix byte for a public key + // whose Y coordingate is odd when serialized according to the hybrid format + // per section 4.3.6 of [ANSI X9.62-1998]. + // + // NOTE: This format makes little sense in practice an therefore this + // package will not produce public keys serialized in this format. However, + // it will parse them since they exist in the wild. + PubKeyFormatHybridOdd byte = 0x07 +) + +// PublicKey provides facilities for efficiently working with secp256k1 public +// keys within this package and includes functions to serialize in both +// uncompressed and compressed SEC (Standards for Efficient Cryptography) +// formats. +type PublicKey struct { + x FieldVal + y FieldVal +} + +// NewPublicKey instantiates a new public key with the given x and y +// coordinates. +// +// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x +// and y coordinates, it allows creation of public keys that are not valid +// points on the secp256k1 curve. The IsOnCurve method of the returned instance +// can be used to determine validity. +func NewPublicKey(x, y *FieldVal) *PublicKey { + var pubKey PublicKey + pubKey.x.Set(x) + pubKey.y.Set(y) + return &pubKey +} + +// ParsePubKey parses a secp256k1 public key encoded according to the format +// specified by ANSI X9.62-1998, which means it is also compatible with the +// SEC (Standards for Efficient Cryptography) specification which is a subset of +// the former. In other words, it supports the uncompressed, compressed, and +// hybrid formats as follows: +// +// Compressed: +// +// <32-byte X coordinate> +// +// Uncompressed: +// +// <32-byte X coordinate><32-byte Y coordinate> +// +// Hybrid: +// +// <32-byte X coordinate><32-byte Y coordinate> +// +// NOTE: The hybrid format makes little sense in practice an therefore this +// package will not produce public keys serialized in this format. However, +// this function will properly parse them since they exist in the wild. +func ParsePubKey(serialized []byte) (key *PublicKey, err error) { + var x, y FieldVal + switch len(serialized) { + case PubKeyBytesLenUncompressed: + // Reject unsupported public key formats for the given length. + format := serialized[0] + switch format { + case PubKeyFormatUncompressed: + case PubKeyFormatHybridEven, PubKeyFormatHybridOdd: + default: + str := fmt.Sprintf("invalid public key: unsupported format: %x", + format) + return nil, makeError(ErrPubKeyInvalidFormat, str) + } + + // Parse the x and y coordinates while ensuring that they are in the + // allowed range. + if overflow := x.SetByteSlice(serialized[1:33]); overflow { + str := "invalid public key: x >= field prime" + return nil, makeError(ErrPubKeyXTooBig, str) + } + if overflow := y.SetByteSlice(serialized[33:]); overflow { + str := "invalid public key: y >= field prime" + return nil, makeError(ErrPubKeyYTooBig, str) + } + + // Ensure the oddness of the y coordinate matches the specified format + // for hybrid public keys. + if format == PubKeyFormatHybridEven || format == PubKeyFormatHybridOdd { + wantOddY := format == PubKeyFormatHybridOdd + if y.IsOdd() != wantOddY { + str := fmt.Sprintf("invalid public key: y oddness does not "+ + "match specified value of %v", wantOddY) + return nil, makeError(ErrPubKeyMismatchedOddness, str) + } + } + + // Reject public keys that are not on the secp256k1 curve. + if !isOnCurve(&x, &y) { + str := fmt.Sprintf("invalid public key: [%v,%v] not on secp256k1 "+ + "curve", x, y) + return nil, makeError(ErrPubKeyNotOnCurve, str) + } + + case PubKeyBytesLenCompressed: + // Reject unsupported public key formats for the given length. + format := serialized[0] + switch format { + case PubKeyFormatCompressedEven, PubKeyFormatCompressedOdd: + default: + str := fmt.Sprintf("invalid public key: unsupported format: %x", + format) + return nil, makeError(ErrPubKeyInvalidFormat, str) + } + + // Parse the x coordinate while ensuring that it is in the allowed + // range. + if overflow := x.SetByteSlice(serialized[1:33]); overflow { + str := "invalid public key: x >= field prime" + return nil, makeError(ErrPubKeyXTooBig, str) + } + + // Attempt to calculate the y coordinate for the given x coordinate such + // that the result pair is a point on the secp256k1 curve and the + // solution with desired oddness is chosen. + wantOddY := format == PubKeyFormatCompressedOdd + if !DecompressY(&x, wantOddY, &y) { + str := fmt.Sprintf("invalid public key: x coordinate %v is not on "+ + "the secp256k1 curve", x) + return nil, makeError(ErrPubKeyNotOnCurve, str) + } + + default: + str := fmt.Sprintf("malformed public key: invalid length: %d", + len(serialized)) + return nil, makeError(ErrPubKeyInvalidLen, str) + } + + return NewPublicKey(&x, &y), nil +} + +// SerializeUncompressed serializes a public key in the 65-byte uncompressed +// format. +func (p PublicKey) SerializeUncompressed() []byte { + // 0x04 || 32-byte x coordinate || 32-byte y coordinate + var b [PubKeyBytesLenUncompressed]byte + b[0] = PubKeyFormatUncompressed + p.x.PutBytesUnchecked(b[1:33]) + p.y.PutBytesUnchecked(b[33:65]) + return b[:] +} + +// SerializeCompressed serializes a public key in the 33-byte compressed format. +func (p PublicKey) SerializeCompressed() []byte { + // Choose the format byte depending on the oddness of the Y coordinate. + format := PubKeyFormatCompressedEven + if p.y.IsOdd() { + format = PubKeyFormatCompressedOdd + } + + // 0x02 or 0x03 || 32-byte x coordinate + var b [PubKeyBytesLenCompressed]byte + b[0] = format + p.x.PutBytesUnchecked(b[1:33]) + return b[:] +} + +// IsEqual compares this public key instance to the one passed, returning true +// if both public keys are equivalent. A public key is equivalent to another, +// if they both have the same X and Y coordinates. +func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool { + return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y) +} + +// AsJacobian converts the public key into a Jacobian point with Z=1 and stores +// the result in the provided result param. This allows the public key to be +// treated a Jacobian point in the secp256k1 group in calculations. +func (p *PublicKey) AsJacobian(result *JacobianPoint) { + result.X.Set(&p.x) + result.Y.Set(&p.y) + result.Z.SetInt(1) +} + +// IsOnCurve returns whether or not the public key represents a point on the +// secp256k1 curve. +func (p *PublicKey) IsOnCurve() bool { + return isOnCurve(&p.x, &p.y) +} diff --git a/vendor/github.com/lestrrat-go/blackmagic/.gitignore b/vendor/github.com/lestrrat-go/blackmagic/.gitignore new file mode 100644 index 0000000000..66fd13c903 --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/blackmagic/LICENSE b/vendor/github.com/lestrrat-go/blackmagic/LICENSE new file mode 100644 index 0000000000..188ea7685c --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lestrrat-go + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/blackmagic/README.md b/vendor/github.com/lestrrat-go/blackmagic/README.md new file mode 100644 index 0000000000..0356f8a72b --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/README.md @@ -0,0 +1,3 @@ +# blackmagic + +Reflect-based black magic. YMMV, and use with caution diff --git a/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go b/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go new file mode 100644 index 0000000000..9c98ac8483 --- /dev/null +++ b/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go @@ -0,0 +1,125 @@ +package blackmagic + +import ( + "fmt" + "reflect" +) + +type errInvalidValue struct{} + +func (*errInvalidValue) Error() string { + return "invalid value (probably an untyped nil)" +} + +// InvalidValueError is a sentinel error that can be used to +// indicate that a value is invalid. This can happen when the +// source value is an untyped nil, and we have no further information +// about the type of the value, obstructing the assignment. +func InvalidValueError() error { + return &errInvalidValue{} +} + +// AssignField is a convenience function to assign a value to +// an optional struct field. In Go, an optional struct field is +// usually denoted by a pointer to T instead of T: +// +// type Object struct { +// Optional *T +// } +// +// This gets a bit cumbersome when you want to assign literals +// or you do not want to worry about taking the address of a +// variable. +// +// Object.Optional = &"foo" // doesn't compile! +// +// Instead you can use this function to do it in one line: +// +// blackmagic.AssignOptionalField(&Object.Optionl, "foo") +func AssignOptionalField(dst, src interface{}) error { + dstRV := reflect.ValueOf(dst) + srcRV := reflect.ValueOf(src) + if dstRV.Kind() != reflect.Pointer || dstRV.Elem().Kind() != reflect.Pointer { + return fmt.Errorf(`dst must be a pointer to a field that is turn a pointer of src (%T)`, src) + } + + if !dstRV.Elem().CanSet() { + return fmt.Errorf(`dst (%T) is not assignable`, dstRV.Elem().Interface()) + } + if !reflect.PointerTo(srcRV.Type()).AssignableTo(dstRV.Elem().Type()) { + return fmt.Errorf(`cannot assign src (%T) to dst (%T)`, src, dst) + } + + ptr := reflect.New(srcRV.Type()) + ptr.Elem().Set(srcRV) + dstRV.Elem().Set(ptr) + return nil +} + +// AssignIfCompatible is a convenience function to safely +// assign arbitrary values. dst must be a pointer to an +// empty interface, or it must be a pointer to a compatible +// variable type that can hold src. +func AssignIfCompatible(dst, src interface{}) error { + orv := reflect.ValueOf(src) // save this value for error reporting + result := orv + + // src can be a pointer or a slice, and the code will slightly change + // depending on this + var srcIsPtr bool + var srcIsSlice bool + switch result.Kind() { + case reflect.Ptr: + srcIsPtr = true + case reflect.Slice: + srcIsSlice = true + } + + rv := reflect.ValueOf(dst) + if rv.Kind() != reflect.Ptr { + return fmt.Errorf(`destination argument to AssignIfCompatible() must be a pointer: %T`, dst) + } + + actualDst := rv + for { + if !actualDst.IsValid() { + return fmt.Errorf(`could not find a valid destination for AssignIfCompatible() (%T)`, dst) + } + if actualDst.CanSet() { + break + } + actualDst = actualDst.Elem() + } + + switch actualDst.Kind() { + case reflect.Interface: + // If it's an interface, we can just assign the pointer to the interface{} + default: + // If it's a pointer to the struct we're looking for, we need to set + // the de-referenced struct + if !srcIsSlice && srcIsPtr { + result = result.Elem() + } + } + + if !result.IsValid() { + // At this point there's nothing we can do. return an error + return fmt.Errorf(`source value is invalid (%T): %w`, src, InvalidValueError()) + } + + if actualDst.Kind() == reflect.Ptr { + actualDst.Set(result.Addr()) + return nil + } + + if !result.Type().AssignableTo(actualDst.Type()) { + return fmt.Errorf(`argument to AssignIfCompatible() must be compatible with %T (was %T)`, orv.Interface(), dst) + } + + if !actualDst.CanSet() { + return fmt.Errorf(`argument to AssignIfCompatible() must be settable`) + } + actualDst.Set(result) + + return nil +} diff --git a/vendor/github.com/lestrrat-go/httpcc/.gitignore b/vendor/github.com/lestrrat-go/httpcc/.gitignore new file mode 100644 index 0000000000..66fd13c903 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/httpcc/LICENSE b/vendor/github.com/lestrrat-go/httpcc/LICENSE new file mode 100644 index 0000000000..963209bfba --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 lestrrat-go + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/httpcc/README.md b/vendor/github.com/lestrrat-go/httpcc/README.md new file mode 100644 index 0000000000..cf2dcb327c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/README.md @@ -0,0 +1,35 @@ +httpcc +====== + +Parses HTTP/1.1 Cache-Control header, and returns a struct that is convenient +for the end-user to do what they will with. + +# Parsing the HTTP Request + +```go +dir, err := httpcc.ParseRequest(req.Header.Get(`Cache-Control`)) +// dir.MaxAge() uint64, bool +// dir.MaxStale() uint64, bool +// dir.MinFresh() uint64, bool +// dir.NoCache() bool +// dir.NoStore() bool +// dir.NoTransform() bool +// dir.OnlyIfCached() bool +// dir.Extensions() map[string]string +``` + +# Parsing the HTTP Response + +```go +directives, err := httpcc.ParseResponse(res.Header.Get(`Cache-Control`)) +// dir.MaxAge() uint64, bool +// dir.MustRevalidate() bool +// dir.NoCache() []string +// dir.NoStore() bool +// dir.NoTransform() bool +// dir.Public() bool +// dir.Private() bool +// dir.SMaxAge() uint64, bool +// dir.Extensions() map[string]string +``` + diff --git a/vendor/github.com/lestrrat-go/httpcc/directives.go b/vendor/github.com/lestrrat-go/httpcc/directives.go new file mode 100644 index 0000000000..86cbbf0b9a --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/directives.go @@ -0,0 +1,117 @@ +package httpcc + +type RequestDirective struct { + maxAge *uint64 + maxStale *uint64 + minFresh *uint64 + noCache bool + noStore bool + noTransform bool + onlyIfCached bool + extensions map[string]string +} + +func (d *RequestDirective) MaxAge() (uint64, bool) { + if v := d.maxAge; v != nil { + return *v, true + } + return 0, false +} + +func (d *RequestDirective) MaxStale() (uint64, bool) { + if v := d.maxStale; v != nil { + return *v, true + } + return 0, false +} + +func (d *RequestDirective) MinFresh() (uint64, bool) { + if v := d.minFresh; v != nil { + return *v, true + } + return 0, false +} + +func (d *RequestDirective) NoCache() bool { + return d.noCache +} + +func (d *RequestDirective) NoStore() bool { + return d.noStore +} + +func (d *RequestDirective) NoTransform() bool { + return d.noTransform +} + +func (d *RequestDirective) OnlyIfCached() bool { + return d.onlyIfCached +} + +func (d *RequestDirective) Extensions() map[string]string { + return d.extensions +} + +func (d *RequestDirective) Extension(s string) string { + return d.extensions[s] +} + +type ResponseDirective struct { + maxAge *uint64 + noCache []string + noStore bool + noTransform bool + public bool + private []string + proxyRevalidate bool + sMaxAge *uint64 + extensions map[string]string +} + +func (d *ResponseDirective) MaxAge() (uint64, bool) { + if v := d.maxAge; v != nil { + return *v, true + } + return 0, false +} + +func (d *ResponseDirective) NoCache() []string { + return d.noCache +} + +func (d *ResponseDirective) NoStore() bool { + return d.noStore +} + +func (d *ResponseDirective) NoTransform() bool { + return d.noTransform +} + +func (d *ResponseDirective) Public() bool { + return d.public +} + +func (d *ResponseDirective) Private() []string { + return d.private +} + +func (d *ResponseDirective) ProxyRevalidate() bool { + return d.proxyRevalidate +} + +func (d *ResponseDirective) SMaxAge() (uint64, bool) { + if v := d.sMaxAge; v != nil { + return *v, true + } + return 0, false +} + +func (d *ResponseDirective) Extensions() map[string]string { + return d.extensions +} + +func (d *ResponseDirective) Extension(s string) string { + return d.extensions[s] +} + + diff --git a/vendor/github.com/lestrrat-go/httpcc/httpcc.go b/vendor/github.com/lestrrat-go/httpcc/httpcc.go new file mode 100644 index 0000000000..14679f9b1c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httpcc/httpcc.go @@ -0,0 +1,310 @@ +package httpcc + +import ( + "bufio" + "fmt" + "strconv" + "strings" + "unicode/utf8" +) + +const ( + // Request Cache-Control directives + MaxAge = "max-age" // used in response as well + MaxStale = "max-stale" + MinFresh = "min-fresh" + NoCache = "no-cache" // used in response as well + NoStore = "no-store" // used in response as well + NoTransform = "no-transform" // used in response as well + OnlyIfCached = "only-if-cached" + + // Response Cache-Control directive + MustRevalidate = "must-revalidate" + Public = "public" + Private = "private" + ProxyRevalidate = "proxy-revalidate" + SMaxAge = "s-maxage" +) + +type TokenPair struct { + Name string + Value string +} + +type TokenValuePolicy int + +const ( + NoArgument TokenValuePolicy = iota + TokenOnly + QuotedStringOnly + AnyTokenValue +) + +type directiveValidator interface { + Validate(string) TokenValuePolicy +} +type directiveValidatorFn func(string) TokenValuePolicy + +func (fn directiveValidatorFn) Validate(ccd string) TokenValuePolicy { + return fn(ccd) +} + +func responseDirectiveValidator(s string) TokenValuePolicy { + switch s { + case MustRevalidate, NoStore, NoTransform, Public, ProxyRevalidate: + return NoArgument + case NoCache, Private: + return QuotedStringOnly + case MaxAge, SMaxAge: + return TokenOnly + default: + return AnyTokenValue + } +} + +func requestDirectiveValidator(s string) TokenValuePolicy { + switch s { + case MaxAge, MaxStale, MinFresh: + return TokenOnly + case NoCache, NoStore, NoTransform, OnlyIfCached: + return NoArgument + default: + return AnyTokenValue + } +} + +// ParseRequestDirective parses a single token. +func ParseRequestDirective(s string) (*TokenPair, error) { + return parseDirective(s, directiveValidatorFn(requestDirectiveValidator)) +} + +func ParseResponseDirective(s string) (*TokenPair, error) { + return parseDirective(s, directiveValidatorFn(responseDirectiveValidator)) +} + +func parseDirective(s string, ccd directiveValidator) (*TokenPair, error) { + s = strings.TrimSpace(s) + + i := strings.IndexByte(s, '=') + if i == -1 { + return &TokenPair{Name: s}, nil + } + + pair := &TokenPair{Name: strings.TrimSpace(s[:i])} + + if len(s) <= i { + // `key=` feels like it's a parse error, but it's HTTP... + // for now, return as if nothing happened. + return pair, nil + } + + v := strings.TrimSpace(s[i+1:]) + switch ccd.Validate(pair.Name) { + case TokenOnly: + if v[0] == '"' { + return nil, fmt.Errorf(`invalid value for %s (quoted string not allowed)`, pair.Name) + } + case QuotedStringOnly: // quoted-string only + if v[0] != '"' { + return nil, fmt.Errorf(`invalid value for %s (bare token not allowed)`, pair.Name) + } + tmp, err := strconv.Unquote(v) + if err != nil { + return nil, fmt.Errorf(`malformed quoted string in token`) + } + v = tmp + case AnyTokenValue: + if v[0] == '"' { + tmp, err := strconv.Unquote(v) + if err != nil { + return nil, fmt.Errorf(`malformed quoted string in token`) + } + v = tmp + } + case NoArgument: + if len(v) > 0 { + return nil, fmt.Errorf(`received argument to directive %s`, pair.Name) + } + } + + pair.Value = v + return pair, nil +} + +func ParseResponseDirectives(s string) ([]*TokenPair, error) { + return parseDirectives(s, ParseResponseDirective) +} + +func ParseRequestDirectives(s string) ([]*TokenPair, error) { + return parseDirectives(s, ParseRequestDirective) +} + +func parseDirectives(s string, p func(string) (*TokenPair, error)) ([]*TokenPair, error) { + scanner := bufio.NewScanner(strings.NewReader(s)) + scanner.Split(scanCommaSeparatedWords) + + var tokens []*TokenPair + for scanner.Scan() { + tok, err := p(scanner.Text()) + if err != nil { + return nil, fmt.Errorf(`failed to parse token #%d: %w`, len(tokens)+1, err) + } + tokens = append(tokens, tok) + } + return tokens, nil +} + +// isSpace reports whether the character is a Unicode white space character. +// We avoid dependency on the unicode package, but check validity of the implementation +// in the tests. +func isSpace(r rune) bool { + if r <= '\u00FF' { + // Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs. + switch r { + case ' ', '\t', '\n', '\v', '\f', '\r': + return true + case '\u0085', '\u00A0': + return true + } + return false + } + // High-valued ones. + if '\u2000' <= r && r <= '\u200a' { + return true + } + switch r { + case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000': + return true + } + return false +} + +func scanCommaSeparatedWords(data []byte, atEOF bool) (advance int, token []byte, err error) { + // Skip leading spaces. + start := 0 + for width := 0; start < len(data); start += width { + var r rune + r, width = utf8.DecodeRune(data[start:]) + if !isSpace(r) { + break + } + } + // Scan until we find a comma. Keep track of consecutive whitespaces + // so we remove them from the end result + var ws int + for width, i := 0, start; i < len(data); i += width { + var r rune + r, width = utf8.DecodeRune(data[i:]) + switch { + case isSpace(r): + ws++ + case r == ',': + return i + width, data[start : i-ws], nil + default: + ws = 0 + } + } + + // If we're at EOF, we have a final, non-empty, non-terminated word. Return it. + if atEOF && len(data) > start { + return len(data), data[start : len(data)-ws], nil + } + + // Request more data. + return start, nil, nil +} + +// ParseRequest parses the content of `Cache-Control` header of an HTTP Request. +func ParseRequest(v string) (*RequestDirective, error) { + var dir RequestDirective + tokens, err := ParseRequestDirectives(v) + if err != nil { + return nil, fmt.Errorf(`failed to parse tokens: %w`, err) + } + + for _, token := range tokens { + name := strings.ToLower(token.Name) + switch name { + case MaxAge: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse max-age: %w`, err) + } + dir.maxAge = &iv + case MaxStale: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse max-stale: %w`, err) + } + dir.maxStale = &iv + case MinFresh: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse min-fresh: %w`, err) + } + dir.minFresh = &iv + case NoCache: + dir.noCache = true + case NoStore: + dir.noStore = true + case NoTransform: + dir.noTransform = true + case OnlyIfCached: + dir.onlyIfCached = true + default: + dir.extensions[token.Name] = token.Value + } + } + return &dir, nil +} + +// ParseResponse parses the content of `Cache-Control` header of an HTTP Response. +func ParseResponse(v string) (*ResponseDirective, error) { + tokens, err := ParseResponseDirectives(v) + if err != nil { + return nil, fmt.Errorf(`failed to parse tokens: %w`, err) + } + + var dir ResponseDirective + dir.extensions = make(map[string]string) + for _, token := range tokens { + name := strings.ToLower(token.Name) + switch name { + case MaxAge: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse max-age: %w`, err) + } + dir.maxAge = &iv + case NoCache: + scanner := bufio.NewScanner(strings.NewReader(token.Value)) + scanner.Split(scanCommaSeparatedWords) + for scanner.Scan() { + dir.noCache = append(dir.noCache, scanner.Text()) + } + case NoStore: + dir.noStore = true + case NoTransform: + dir.noTransform = true + case Public: + dir.public = true + case Private: + scanner := bufio.NewScanner(strings.NewReader(token.Value)) + scanner.Split(scanCommaSeparatedWords) + for scanner.Scan() { + dir.private = append(dir.private, scanner.Text()) + } + case ProxyRevalidate: + dir.proxyRevalidate = true + case SMaxAge: + iv, err := strconv.ParseUint(token.Value, 10, 64) + if err != nil { + return nil, fmt.Errorf(`failed to parse s-maxage: %w`, err) + } + dir.sMaxAge = &iv + default: + dir.extensions[token.Name] = token.Value + } + } + return &dir, nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/.gitignore b/vendor/github.com/lestrrat-go/httprc/v3/.gitignore new file mode 100644 index 0000000000..66fd13c903 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/httprc/v3/.golangci.yml b/vendor/github.com/lestrrat-go/httprc/v3/.golangci.yml new file mode 100644 index 0000000000..a51b41b4a5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/.golangci.yml @@ -0,0 +1,93 @@ +version: "2" +linters: + default: all + disable: + - cyclop + - depguard + - dupl + - errorlint + - exhaustive + - forbidigo + - funcorder + - funlen + - gochecknoglobals + - gochecknoinits + - gocognit + - gocritic + - gocyclo + - godot + - godox + - gosec + - gosmopolitan + - govet + - inamedparam + - ireturn + - lll + - maintidx + - makezero + - mnd + - nakedret + - nestif + - nlreturn + - nonamedreturns + - paralleltest + - tagliatelle + - testpackage + - thelper + - varnamelen + - wrapcheck + - wsl + settings: + govet: + disable: + - shadow + - fieldalignment + enable-all: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - staticcheck + path: /*.go + text: 'ST1003: should not use underscores in package names' + - linters: + - revive + path: /*.go + text: don't use an underscore in package name + - linters: + - contextcheck + - exhaustruct + path: /*.go + - linters: + - errcheck + path: /main.go + - linters: + - errcheck + - errchkjson + - forcetypeassert + path: /*_test.go + - linters: + - forbidigo + path: /*_example_test.go + paths: + - third_party$ + - builtin$ + - examples$ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/lestrrat-go/httprc/v3/Changes b/vendor/github.com/lestrrat-go/httprc/v3/Changes new file mode 100644 index 0000000000..3c82040d43 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/Changes @@ -0,0 +1,27 @@ +Changes +======= + +v3.0.0 UNRELEASED +[Breaking Changes] + * The entire API has been re-imagined for Go versions that allow typed parameters + +v2.0.0 19 Feb 2024 +[Breaking Changes] + * `Fetcher` type is no longer available. You probably want to provide + a customg HTTP client instead via httprc.WithHTTPClient()). + * + +v1.0.4 19 Jul 2022 + * Fix sloppy API breakage + +v1.0.3 19 Jul 2022 + * Fix queue insertion in the middle of the queue (#7) + +v1.0.2 13 Jun 2022 + * Properly release a lock when the fetch fails (#5) + +v1.0.1 29 Mar 2022 + * Bump dependency for github.com/lestrrat-go/httpcc to v1.0.1 + +v1.0.0 29 Mar 2022 + * Initial release, refactored out of github.com/lestrrat-go/jwx diff --git a/vendor/github.com/lestrrat-go/httprc/v3/LICENSE b/vendor/github.com/lestrrat-go/httprc/v3/LICENSE new file mode 100644 index 0000000000..3e196892ca --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 lestrrat + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/httprc/v3/README.md b/vendor/github.com/lestrrat-go/httprc/v3/README.md new file mode 100644 index 0000000000..68239669a2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/README.md @@ -0,0 +1,172 @@ +# github.com/lestrrat-go/httprc/v3 ![](https://github.com/lestrrat-go/httprc/v3/workflows/CI/badge.svg) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/httprc/v3.svg)](https://pkg.go.dev/github.com/lestrrat-go/httprc/v3) + +`httprc` is a HTTP "Refresh" Cache. Its aim is to cache a remote resource that +can be fetched via HTTP, but keep the cached content up-to-date based on periodic +refreshing. + +# Client + +A `httprc.Client` object is comprised of 3 parts: The user-facing controller API, +the main controller loop, and set of workers that perform the actual fetching. + +The user-facing controller API is the object returned when you call `(httprc.Client).Start`. + +```go +ctrl, _ := client.Start(ctx) +``` + +# Controller API + +The controller API gives you access to the controller backend that runs asynchronously. +All methods take a `context.Context` object because they potentially block. You should +be careful to use `context.WithTimeout` to properly set a timeout if you cannot tolerate +a blocking operation. + +# Main Controller Loop + +The main controller loop is run asynchronously to the controller API. It is single threaded, +and it has two reponsibilities. + +The first is to receive commands from the controller API, +and appropriately modify the state of the goroutine, i.e. modify the list of resources +it is watching, performing forced refreshes, etc. + +The other is to periodically wake up and go through the list of resources and re-fetch +ones that are past their TTL (in reality, each resource carry a "next-check" time, not +a TTL). The main controller loop itself does nothing more: it just kicks these checks periodically. + +The interval between fetches is changed dynamically based on either the metadata carried +with the HTTP responses, such as `Cache-Control` and `Expires` headers, or a constant +interval set by the user for a given resource. Between these values, the main controller loop +will pick the shortest interval (but no less than 1 second) and checks if resources +need updating based on that value. + +For example, if a resource A has an expiry of 10 minutes and if resource has an expiry of 5 +minutes, the main controller loop will attempt to wake up roughly every 5 minutes to check +on the resources. + +When the controller loop detects that a resource needs to be checked for freshness, +it will send the resource to the worker pool to be synced. + +# Interval calculation + +After the resource is synced, the next fetch is scheduled. The interval to the next +fetch is calculated either by using constant intervals, or by heuristics using values +from the `http.Response` object. + +If the constant interval is specified, no extra calculation is performed. If you specify +a constant interval of 15 minutes, the resource will be checked every 15 minutes. This is +predictable and reliable, but not necessarily efficient. + +If you do not specify a constant interval, the HTTP response is analyzed for +values in `Cache-Control` and `Expires` headers. These values will be compared against +a maximum and minimum interval values, which default to 30 days and 15 minutes, respectively. +If the values obtained from the headers fall within that range, the value from the header is +used. If the value is larger than the maximum, the maximum is used. If the value is lower +than the minimum, the minimum is used. + +# SYNOPSIS + + +```go +package httprc_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "time" + + "github.com/lestrrat-go/httprc/v3" +) + +func ExampleClient() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + type HelloWorld struct { + Hello string `json:"hello"` + } + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + json.NewEncoder(w).Encode(map[string]string{"hello": "world"}) + })) + + options := []httprc.NewClientOption{ + // By default the client will allow all URLs (which is what the option + // below is explicitly specifying). If you want to restrict what URLs + // are allowed, you can specify another whitelist. + // + // httprc.WithWhitelist(httprc.NewInsecureWhitelist()), + } + // If you would like to handle errors from asynchronous workers, you can specify a error sink. + // This is disabled in this example because the trace logs are dynamic + // and thus would interfere with the runnable example test. + // options = append(options, httprc.WithErrorSink(errsink.NewSlog(slog.New(slog.NewJSONHandler(os.Stdout, nil))))) + + // If you would like to see the trace logs, you can specify a trace sink. + // This is disabled in this example because the trace logs are dynamic + // and thus would interfere with the runnable example test. + // options = append(options, httprc.WithTraceSink(tracesink.NewSlog(slog.New(slog.NewJSONHandler(os.Stdout, nil))))) + + // Create a new client + cl := httprc.NewClient(options...) + + // Start the client, and obtain a Controller object + ctrl, err := cl.Start(ctx) + if err != nil { + fmt.Println(err.Error()) + return + } + // The following is required if you want to make sure that there are no + // dangling goroutines hanging around when you exit. For example, if you + // are running tests to check for goroutine leaks, you should call this + // function before the end of your test. + defer ctrl.Shutdown(time.Second) + + // Create a new resource that is synchronized every so often + // + // By default the client will attempt to fetch the resource once + // as soon as it can, and then if no other metadata is provided, + // it will fetch the resource every 15 minutes. + // + // If the resource responds with a Cache-Control/Expires header, + // the client will attempt to respect that, and will try to fetch + // the resource again based on the values obatained from the headers. + r, err := httprc.NewResource[HelloWorld](srv.URL, httprc.JSONTransformer[HelloWorld]()) + if err != nil { + fmt.Println(err.Error()) + return + } + + // Add the resource to the controller, so that it starts fetching. + // By default, a call to `Add()` will block until the first fetch + // succeeds, via an implicit call to `r.Ready()` + // You can change this behavior if you specify the `WithWaitReady(false)` + // option. + ctrl.Add(ctx, r) + + // if you specified `httprc.WithWaitReady(false)` option, the fetch will happen + // "soon", but you're not guaranteed that it will happen before the next + // call to `Lookup()`. If you want to make sure that the resource is ready, + // you can call `Ready()` like so: + /* + { + tctx, tcancel := context.WithTimeout(ctx, time.Second) + defer tcancel() + if err := r.Ready(tctx); err != nil { + fmt.Println(err.Error()) + return + } + } + */ + m := r.Resource() + fmt.Println(m.Hello) + // OUTPUT: + // world +} +``` +source: [client_example_test.go](https://github.com/lestrrat-go/httprc/blob/refs/heads/v3/client_example_test.go) + diff --git a/vendor/github.com/lestrrat-go/httprc/v3/backend.go b/vendor/github.com/lestrrat-go/httprc/v3/backend.go new file mode 100644 index 0000000000..7d4fb496aa --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/backend.go @@ -0,0 +1,237 @@ +package httprc + +import ( + "context" + "fmt" + "sync" + "time" +) + +func (c *ctrlBackend) adjustInterval(ctx context.Context, req adjustIntervalRequest) { + interval := roundupToSeconds(time.Until(req.resource.Next())) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: got adjust request (current tick interval=%s, next for %q=%s)", c.tickInterval, req.resource.URL(), interval)) + + if interval < time.Second { + interval = time.Second + } + + if c.tickInterval < interval { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: no adjusting required (time to next check %s > current tick interval %s)", interval, c.tickInterval)) + } else { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: adjusting tick interval to %s", interval)) + c.tickInterval = interval + c.check.Reset(interval) + } +} + +func (c *ctrlBackend) addResource(ctx context.Context, req addRequest) { + r := req.resource + if _, ok := c.items[r.URL()]; ok { + // Already exists + sendReply(ctx, req.reply, struct{}{}, errResourceAlreadyExists) + return + } + c.items[r.URL()] = r + + if r.MaxInterval() == 0 { + r.SetMaxInterval(c.defaultMaxInterval) + } + + if r.MinInterval() == 0 { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: set minimum interval to %s", c.defaultMinInterval)) + r.SetMinInterval(c.defaultMinInterval) + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: added resource %q", r.URL())) + sendReply(ctx, req.reply, struct{}{}, nil) + c.SetTickInterval(time.Nanosecond) +} + +func (c *ctrlBackend) rmResource(ctx context.Context, req rmRequest) { + u := req.u + if _, ok := c.items[u]; !ok { + sendReply(ctx, req.reply, struct{}{}, errResourceNotFound) + return + } + + delete(c.items, u) + + minInterval := oneDay + for _, item := range c.items { + if d := item.MinInterval(); d < minInterval { + minInterval = d + } + } + + close(req.reply) + c.check.Reset(minInterval) +} + +func (c *ctrlBackend) refreshResource(ctx context.Context, req refreshRequest) { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] START %q", req.u)) + defer c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] END %q", req.u)) + u := req.u + r, ok := c.items[u] + if !ok { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] %s is not registered", req.u)) + sendReply(ctx, req.reply, struct{}{}, errResourceNotFound) + return + } + + // Make sure it's ready + if err := r.Ready(ctx); err != nil { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] %s did not become ready: %v", req.u, err)) + sendReply(ctx, req.reply, struct{}{}, err) + return + } + + r.SetNext(time.Unix(0, 0)) + sendWorkerSynchronous(ctx, c.syncoutgoing, synchronousRequest{ + resource: r, + reply: req.reply, + }) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: [refresh] sync request for %s sent to worker pool", req.u)) +} + +func (c *ctrlBackend) lookupResource(ctx context.Context, req lookupRequest) { + u := req.u + r, ok := c.items[u] + if !ok { + sendReply(ctx, req.reply, nil, errResourceNotFound) + return + } + sendReply(ctx, req.reply, r, nil) +} + +func (c *ctrlBackend) handleRequest(ctx context.Context, req any) { + switch req := req.(type) { + case adjustIntervalRequest: + c.adjustInterval(ctx, req) + case addRequest: + c.addResource(ctx, req) + case rmRequest: + c.rmResource(ctx, req) + case refreshRequest: + c.refreshResource(ctx, req) + case lookupRequest: + c.lookupResource(ctx, req) + default: + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: unknown request type %T", req)) + } +} + +func sendWorker(ctx context.Context, ch chan Resource, r Resource) { + r.SetBusy(true) + select { + case <-ctx.Done(): + case ch <- r: + } +} + +func sendWorkerSynchronous(ctx context.Context, ch chan synchronousRequest, r synchronousRequest) { + r.resource.SetBusy(true) + select { + case <-ctx.Done(): + case ch <- r: + } +} + +func sendReply[T any](ctx context.Context, ch chan backendResponse[T], v T, err error) { + defer close(ch) + select { + case <-ctx.Done(): + case ch <- backendResponse[T]{payload: v, err: err}: + } +} + +type ctrlBackend struct { + items map[string]Resource + outgoing chan Resource + syncoutgoing chan synchronousRequest + incoming chan any // incoming requests to the controller + traceSink TraceSink + tickInterval time.Duration + check *time.Ticker + defaultMaxInterval time.Duration + defaultMinInterval time.Duration +} + +func (c *ctrlBackend) loop(ctx context.Context, readywg, donewg *sync.WaitGroup) { + c.traceSink.Put(ctx, "httprc controller: starting main controller loop") + readywg.Done() + defer c.traceSink.Put(ctx, "httprc controller: stopping main controller loop") + defer donewg.Done() + for { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: waiting for request or tick (tick interval=%s)", c.tickInterval)) + select { + case req := <-c.incoming: + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: got request %T", req)) + c.handleRequest(ctx, req) + case t := <-c.check.C: + c.periodicCheck(ctx, t) + case <-ctx.Done(): + return + } + } +} + +func (c *ctrlBackend) periodicCheck(ctx context.Context, t time.Time) { + c.traceSink.Put(ctx, "httprc controller: START periodic check") + defer c.traceSink.Put(ctx, "httprc controller: END periodic check") + var minNext time.Time + var dispatched int + minInterval := -1 * time.Second + for _, item := range c.items { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: checking resource %q", item.URL())) + + next := item.Next() + if minNext.IsZero() || next.Before(minNext) { + minNext = next + } + + if interval := item.MinInterval(); minInterval < 0 || interval < minInterval { + minInterval = interval + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resource %q isBusy=%t, next(%s).After(%s)=%t", item.URL(), item.IsBusy(), next, t, next.After(t))) + if item.IsBusy() || next.After(t) { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resource %q is busy or not ready yet, skipping", item.URL())) + continue + } + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resource %q is ready, dispatching to worker pool", item.URL())) + + dispatched++ + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: dispatching resource %q to worker pool", item.URL())) + sendWorker(ctx, c.outgoing, item) + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: dispatched %d resources", dispatched)) + + // Next check is always at the earliest next check + 1 second. + // The extra second makes sure that we are _past_ the actual next check time + // so we can send the resource to the worker pool + if interval := time.Until(minNext); interval > 0 { + c.SetTickInterval(roundupToSeconds(interval) + time.Second) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resetting check intervanl to %s", c.tickInterval)) + } else { + // if we got here, either we have no resources, or all resources are busy. + // In this state, it's possible that the interval is less than 1 second, + // because we previously set it to a small value for an immediate refresh. + // in this case, we want to reset it to a sane value + if c.tickInterval < time.Second { + c.SetTickInterval(minInterval) + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: resetting check intervanl to %s after forced refresh", c.tickInterval)) + } + } + + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: next check in %s", c.tickInterval)) +} + +func (c *ctrlBackend) SetTickInterval(d time.Duration) { + // TODO synchronize + if d <= 0 { + d = time.Second // ensure positive interval + } + c.tickInterval = d + c.check.Reset(d) +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/client.go b/vendor/github.com/lestrrat-go/httprc/v3/client.go new file mode 100644 index 0000000000..75ac3fc188 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/client.go @@ -0,0 +1,183 @@ +package httprc + +import ( + "context" + "net/http" + "sync" + "time" + + "github.com/lestrrat-go/httprc/v3/errsink" + "github.com/lestrrat-go/httprc/v3/proxysink" + "github.com/lestrrat-go/httprc/v3/tracesink" +) + +// setupSink creates and starts a proxy for the given sink if it's not a Nop sink +// Returns the sink to use and a cancel function that should be chained with the original cancel +func setupSink[T any, S proxysink.Backend[T], NopType any](ctx context.Context, sink S, wg *sync.WaitGroup) (S, context.CancelFunc) { + if _, ok := any(sink).(NopType); ok { + return sink, func() {} + } + + proxy := proxysink.New[T](sink) + wg.Add(1) + go func(ctx context.Context, wg *sync.WaitGroup, proxy *proxysink.Proxy[T]) { + defer wg.Done() + proxy.Run(ctx) + }(ctx, wg, proxy) + + // proxy can be converted to one of the sink subtypes + s, ok := any(proxy).(S) + if !ok { + panic("type assertion failed: proxy cannot be converted to type S") + } + return s, proxy.Close +} + +// Client is the main entry point for the httprc package. +type Client struct { + mu sync.Mutex + httpcl HTTPClient + numWorkers int + running bool + errSink ErrorSink + traceSink TraceSink + wl Whitelist + defaultMaxInterval time.Duration + defaultMinInterval time.Duration +} + +// NewClient creates a new `httprc.Client` object. +// +// By default ALL urls are allowed. This may not be suitable for you if +// are using this in a production environment. You are encouraged to specify +// a whitelist using the `WithWhitelist` option. +func NewClient(options ...NewClientOption) *Client { + //nolint:staticcheck + var errSink ErrorSink = errsink.NewNop() + //nolint:staticcheck + var traceSink TraceSink = tracesink.NewNop() + var wl Whitelist = InsecureWhitelist{} + var httpcl HTTPClient = http.DefaultClient + + defaultMinInterval := DefaultMinInterval + defaultMaxInterval := DefaultMaxInterval + + numWorkers := DefaultWorkers + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identHTTPClient{}: + httpcl = option.Value().(HTTPClient) + case identWorkers{}: + numWorkers = option.Value().(int) + case identErrorSink{}: + errSink = option.Value().(ErrorSink) + case identTraceSink{}: + traceSink = option.Value().(TraceSink) + case identWhitelist{}: + wl = option.Value().(Whitelist) + } + } + + if numWorkers <= 0 { + numWorkers = 1 + } + return &Client{ + httpcl: httpcl, + numWorkers: numWorkers, + errSink: errSink, + traceSink: traceSink, + wl: wl, + + defaultMinInterval: defaultMinInterval, + defaultMaxInterval: defaultMaxInterval, + } +} + +// Start sets the client into motion. It will start a number of worker goroutines, +// and return a Controller object that you can use to control the execution of +// the client. +// +// If you attempt to call Start more than once, it will return an error. +func (c *Client) Start(octx context.Context) (Controller, error) { + c.mu.Lock() + if c.running { + c.mu.Unlock() + return nil, errAlreadyRunning + } + c.running = true + c.mu.Unlock() + + // DON'T CANCEL THIS IN THIS METHOD! It's the responsibility of the + // controller to cancel this context. + ctx, cancel := context.WithCancel(octx) + + var donewg sync.WaitGroup + + // start proxy goroutines that will accept sink requests + // and forward them to the appropriate sink + errSink, errCancel := setupSink[error, ErrorSink, errsink.Nop](ctx, c.errSink, &donewg) + traceSink, traceCancel := setupSink[string, TraceSink, tracesink.Nop](ctx, c.traceSink, &donewg) + + // Chain the cancel functions + ocancel := cancel + cancel = func() { + ocancel() + errCancel() + traceCancel() + } + + chbuf := c.numWorkers + 1 + incoming := make(chan any, chbuf) + outgoing := make(chan Resource, chbuf) + syncoutgoing := make(chan synchronousRequest, chbuf) + + var readywg sync.WaitGroup + readywg.Add(c.numWorkers) + donewg.Add(c.numWorkers) + for range c.numWorkers { + wrk := worker{ + incoming: incoming, + next: outgoing, + nextsync: syncoutgoing, + errSink: errSink, + traceSink: traceSink, + httpcl: c.httpcl, + } + go wrk.Run(ctx, &readywg, &donewg) + } + + tickInterval := oneDay + ctrl := &controller{ + cancel: cancel, + incoming: incoming, + shutdown: make(chan struct{}), + traceSink: traceSink, + wl: c.wl, + } + + backend := &ctrlBackend{ + items: make(map[string]Resource), + outgoing: outgoing, + syncoutgoing: syncoutgoing, + incoming: incoming, + traceSink: traceSink, + tickInterval: tickInterval, + check: time.NewTicker(tickInterval), + + defaultMinInterval: c.defaultMinInterval, + defaultMaxInterval: c.defaultMaxInterval, + } + donewg.Add(1) + readywg.Add(1) + go backend.loop(ctx, &readywg, &donewg) + + go func(wg *sync.WaitGroup, ch chan struct{}) { + wg.Wait() + close(ch) + }(&donewg, ctrl.shutdown) + + readywg.Wait() + + return ctrl, nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/controller.go b/vendor/github.com/lestrrat-go/httprc/v3/controller.go new file mode 100644 index 0000000000..ae2eb218e4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/controller.go @@ -0,0 +1,186 @@ +package httprc + +import ( + "context" + "fmt" + "time" +) + +type Controller interface { + // Add adds a new `http.Resource` to the controller. If the resource already exists, + // it will return an error. + Add(context.Context, Resource, ...AddOption) error + + // Lookup a `httprc.Resource` by its URL. If the resource does not exist, it + // will return an error. + Lookup(context.Context, string) (Resource, error) + + // Remove a `httprc.Resource` from the controller by its URL. If the resource does + // not exist, it will return an error. + Remove(context.Context, string) error + + // Refresh forces a resource to be refreshed immediately. If the resource does + // not exist, or if the refresh fails, it will return an error. + Refresh(context.Context, string) error + + ShutdownContext(context.Context) error + Shutdown(time.Duration) error +} + +type controller struct { + cancel context.CancelFunc + incoming chan any // incoming requests to the controller + shutdown chan struct{} + traceSink TraceSink + wl Whitelist +} + +// Shutdown is a convenience function that calls ShutdownContext with a +// context that has a timeout of `timeout`. +func (c *controller) Shutdown(timeout time.Duration) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + return c.ShutdownContext(ctx) +} + +// ShutdownContext stops the client and all associated goroutines, and waits for them +// to finish. If the context is canceled, the function will return immediately: +// there fore you should not use the context you used to start the client (because +// presumably it's already canceled). +// +// Waiting for the client shutdown will also ensure that all sinks are properly +// flushed. +func (c *controller) ShutdownContext(ctx context.Context) error { + c.cancel() + + select { + case <-ctx.Done(): + return ctx.Err() + case <-c.shutdown: + return nil + } +} + +type ctrlRequest[T any] struct { + reply chan T + resource Resource + u string +} +type addRequest ctrlRequest[backendResponse[struct{}]] +type rmRequest ctrlRequest[backendResponse[struct{}]] +type refreshRequest ctrlRequest[backendResponse[struct{}]] +type lookupRequest ctrlRequest[backendResponse[Resource]] +type synchronousRequest ctrlRequest[backendResponse[struct{}]] +type adjustIntervalRequest struct { + resource Resource +} + +type backendResponse[T any] struct { + payload T + err error +} + +func sendBackend[TReq any, TB any](ctx context.Context, backendCh chan any, v TReq, replyCh chan backendResponse[TB]) (TB, error) { + select { + case <-ctx.Done(): + case backendCh <- v: + } + + select { + case <-ctx.Done(): + var zero TB + return zero, ctx.Err() + case res := <-replyCh: + return res.payload, res.err + } +} + +// Lookup returns a resource by its URL. If the resource does not exist, it +// will return an error. +// +// Unfortunately, due to the way typed parameters are handled in Go, we can only +// return a Resource object (and not a ResourceBase[T] object). This means that +// you will either need to use the `Resource.Get()` method or use a type +// assertion to obtain a `ResourceBase[T]` to get to the actual object you are +// looking for +func (c *controller) Lookup(ctx context.Context, u string) (Resource, error) { + reply := make(chan backendResponse[Resource], 1) + req := lookupRequest{ + reply: reply, + u: u, + } + return sendBackend[lookupRequest, Resource](ctx, c.incoming, req, reply) +} + +// Add adds a new resource to the controller. If the resource already +// exists, it will return an error. +// +// By default this function will automatically wait for the resource to be +// fetched once (by calling `r.Ready()`). Note that the `r.Ready()` call will NOT +// timeout unless you configure your context object with `context.WithTimeout`. +// To disable waiting, you can specify the `WithWaitReady(false)` option. +func (c *controller) Add(ctx context.Context, r Resource, options ...AddOption) error { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: START Add(%q)", r.URL())) + defer c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: END Add(%q)", r.URL())) + waitReady := true + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identWaitReady{}: + waitReady = option.(addOption).Value().(bool) + } + } + + if !c.wl.IsAllowed(r.URL()) { + return fmt.Errorf(`httprc.Controller.AddResource: cannot add %q: %w`, r.URL(), errBlockedByWhitelist) + } + + reply := make(chan backendResponse[struct{}], 1) + req := addRequest{ + reply: reply, + resource: r, + } + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: sending add request for %q to backend", r.URL())) + if _, err := sendBackend[addRequest, struct{}](ctx, c.incoming, req, reply); err != nil { + return err + } + + if waitReady { + c.traceSink.Put(ctx, fmt.Sprintf("httprc controller: waiting for resource %q to be ready", r.URL())) + if err := r.Ready(ctx); err != nil { + return err + } + } + return nil +} + +// Remove removes a resource from the controller. If the resource does +// not exist, it will return an error. +func (c *controller) Remove(ctx context.Context, u string) error { + reply := make(chan backendResponse[struct{}], 1) + req := rmRequest{ + reply: reply, + u: u, + } + if _, err := sendBackend[rmRequest, struct{}](ctx, c.incoming, req, reply); err != nil { + return err + } + return nil +} + +// Refresh forces a resource to be refreshed immediately. If the resource does +// not exist, or if the refresh fails, it will return an error. +// +// This function is synchronous, and will block until the resource has been refreshed. +func (c *controller) Refresh(ctx context.Context, u string) error { + reply := make(chan backendResponse[struct{}], 1) + req := refreshRequest{ + reply: reply, + u: u, + } + + if _, err := sendBackend[refreshRequest, struct{}](ctx, c.incoming, req, reply); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/errors.go b/vendor/github.com/lestrrat-go/httprc/v3/errors.go new file mode 100644 index 0000000000..1152ba947f --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/errors.go @@ -0,0 +1,57 @@ +package httprc + +import "errors" + +var errResourceAlreadyExists = errors.New(`resource already exists`) + +func ErrResourceAlreadyExists() error { + return errResourceAlreadyExists +} + +var errAlreadyRunning = errors.New(`client is already running`) + +func ErrAlreadyRunning() error { + return errAlreadyRunning +} + +var errResourceNotFound = errors.New(`resource not found`) + +func ErrResourceNotFound() error { + return errResourceNotFound +} + +var errTransformerRequired = errors.New(`transformer is required`) + +func ErrTransformerRequired() error { + return errTransformerRequired +} + +var errURLCannotBeEmpty = errors.New(`URL cannot be empty`) + +func ErrURLCannotBeEmpty() error { + return errURLCannotBeEmpty +} + +var errUnexpectedStatusCode = errors.New(`unexpected status code`) + +func ErrUnexpectedStatusCode() error { + return errUnexpectedStatusCode +} + +var errTransformerFailed = errors.New(`failed to transform response body`) + +func ErrTransformerFailed() error { + return errTransformerFailed +} + +var errRecoveredFromPanic = errors.New(`recovered from panic`) + +func ErrRecoveredFromPanic() error { + return errRecoveredFromPanic +} + +var errBlockedByWhitelist = errors.New(`blocked by whitelist`) + +func ErrBlockedByWhitelist() error { + return errBlockedByWhitelist +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/errsink/errsink.go b/vendor/github.com/lestrrat-go/httprc/v3/errsink/errsink.go new file mode 100644 index 0000000000..03d128ffcd --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/errsink/errsink.go @@ -0,0 +1,59 @@ +package errsink + +import ( + "context" + "log/slog" +) + +type Interface interface { + Put(context.Context, error) +} + +// Nop is an ErrorSink that does nothing. It does not require +// any initialization, so the zero value can be used. +type Nop struct{} + +// NewNop returns a new NopErrorSink object. The constructor +// is provided for consistency. +func NewNop() Interface { + return Nop{} +} + +// Put for NopErrorSink does nothing. +func (Nop) Put(context.Context, error) {} + +type SlogLogger interface { + Log(context.Context, slog.Level, string, ...any) +} + +type slogSink struct { + logger SlogLogger +} + +// NewSlog returns a new ErrorSink that logs errors using the provided slog.Logger +func NewSlog(l SlogLogger) Interface { + return &slogSink{ + logger: l, + } +} + +func (s *slogSink) Put(ctx context.Context, v error) { + s.logger.Log(ctx, slog.LevelError, v.Error()) +} + +// FuncSink is an ErrorSink that calls a function with the error. +type FuncSink struct { + fn func(context.Context, error) +} + +// NewFunc returns a new FuncSink that calls the provided function with errors. +func NewFunc(fn func(context.Context, error)) Interface { + return &FuncSink{fn: fn} +} + +// Put calls the function with the error. +func (f *FuncSink) Put(ctx context.Context, err error) { + if f.fn != nil { + f.fn(ctx, err) + } +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/httprc.go b/vendor/github.com/lestrrat-go/httprc/v3/httprc.go new file mode 100644 index 0000000000..fc324b771f --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/httprc.go @@ -0,0 +1,90 @@ +package httprc + +import ( + "context" + "net/http" + "time" + + "github.com/lestrrat-go/httprc/v3/errsink" + "github.com/lestrrat-go/httprc/v3/tracesink" +) + +// Buffer size constants +const ( + // ReadBufferSize is the default buffer size for reading HTTP responses (10MB) + ReadBufferSize = 1024 * 1024 * 10 + // MaxBufferSize is the maximum allowed buffer size (1GB) + MaxBufferSize = 1024 * 1024 * 1000 +) + +// Client worker constants +const ( + // DefaultWorkers is the default number of worker goroutines + DefaultWorkers = 5 +) + +// Interval constants +const ( + // DefaultMaxInterval is the default maximum interval between fetches (30 days) + DefaultMaxInterval = 24 * time.Hour * 30 + // DefaultMinInterval is the default minimum interval between fetches (15 minutes) + DefaultMinInterval = 15 * time.Minute + // oneDay is used internally for time calculations + oneDay = 24 * time.Hour +) + +// utility to round up intervals to the nearest second +func roundupToSeconds(d time.Duration) time.Duration { + if diff := d % time.Second; diff > 0 { + return d + time.Second - diff + } + return d +} + +// ErrorSink is an interface that abstracts a sink for errors. +type ErrorSink = errsink.Interface + +type TraceSink = tracesink.Interface + +// HTTPClient is an interface that abstracts a "net/http".Client, so that +// users can provide their own implementation of the HTTP client, if need be. +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} + +// Transformer is used to convert the body of an HTTP response into an appropriate +// object of type T. +type Transformer[T any] interface { + Transform(context.Context, *http.Response) (T, error) +} + +// TransformFunc is a function type that implements the Transformer interface. +type TransformFunc[T any] func(context.Context, *http.Response) (T, error) + +func (f TransformFunc[T]) Transform(ctx context.Context, res *http.Response) (T, error) { + return f(ctx, res) +} + +// Resource is a single resource that can be retrieved via HTTP, and (possibly) transformed +// into an arbitrary object type. +// +// Realistically, there is no need for third-parties to implement this interface. This exists +// to provide a way to aggregate `httprc.ResourceBase` objects with different specialized types +// into a single collection. +// +// See ResourceBase for details +type Resource interface { //nolint:interfacebloat + Get(any) error + Next() time.Time + SetNext(time.Time) + URL() string + Sync(context.Context) error + ConstantInterval() time.Duration + MaxInterval() time.Duration + SetMaxInterval(time.Duration) + MinInterval() time.Duration + SetMinInterval(time.Duration) + IsBusy() bool + SetBusy(bool) + Ready(context.Context) error +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/options.go b/vendor/github.com/lestrrat-go/httprc/v3/options.go new file mode 100644 index 0000000000..3f07b5671c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/options.go @@ -0,0 +1,144 @@ +package httprc + +import ( + "time" + + "github.com/lestrrat-go/option" +) + +type NewClientOption interface { + option.Interface + newClientOption() +} + +type newClientOption struct { + option.Interface +} + +func (newClientOption) newClientOption() {} + +type identWorkers struct{} + +// WithWorkers specifies the number of concurrent workers to use for the client. +// If n is less than or equal to 0, the client will use a single worker. +func WithWorkers(n int) NewClientOption { + return newClientOption{option.New(identWorkers{}, n)} +} + +type identErrorSink struct{} + +// WithErrorSink specifies the error sink to use for the client. +// If not specified, the client will use a NopErrorSink. +func WithErrorSink(sink ErrorSink) NewClientOption { + return newClientOption{option.New(identErrorSink{}, sink)} +} + +type identTraceSink struct{} + +// WithTraceSink specifies the trace sink to use for the client. +// If not specified, the client will use a NopTraceSink. +func WithTraceSink(sink TraceSink) NewClientOption { + return newClientOption{option.New(identTraceSink{}, sink)} +} + +type identWhitelist struct{} + +// WithWhitelist specifies the whitelist to use for the client. +// If not specified, the client will use a BlockAllWhitelist. +func WithWhitelist(wl Whitelist) NewClientOption { + return newClientOption{option.New(identWhitelist{}, wl)} +} + +type NewResourceOption interface { + option.Interface + newResourceOption() +} + +type newResourceOption struct { + option.Interface +} + +func (newResourceOption) newResourceOption() {} + +type NewClientResourceOption interface { + option.Interface + newResourceOption() + newClientOption() +} + +type newClientResourceOption struct { + option.Interface +} + +func (newClientResourceOption) newResourceOption() {} +func (newClientResourceOption) newClientOption() {} + +type identHTTPClient struct{} + +// WithHTTPClient specifies the HTTP client to use for the client. +// If not specified, the client will use http.DefaultClient. +// +// This option can be passed to NewClient or NewResource. +func WithHTTPClient(cl HTTPClient) NewClientResourceOption { + return newClientResourceOption{option.New(identHTTPClient{}, cl)} +} + +type identMinimumInterval struct{} + +// WithMinInterval specifies the minimum interval between fetches. +// +// This option affects the dynamic calculation of the interval between fetches. +// If the value calculated from the http.Response is less than the this value, +// the client will use this value instead. +func WithMinInterval(d time.Duration) NewResourceOption { + return newResourceOption{option.New(identMinimumInterval{}, d)} +} + +type identMaximumInterval struct{} + +// WithMaxInterval specifies the maximum interval between fetches. +// +// This option affects the dynamic calculation of the interval between fetches. +// If the value calculated from the http.Response is greater than the this value, +// the client will use this value instead. +func WithMaxInterval(d time.Duration) NewResourceOption { + return newResourceOption{option.New(identMaximumInterval{}, d)} +} + +type identConstantInterval struct{} + +// WithConstantInterval specifies the interval between fetches. When you +// specify this option, the client will fetch the resource at the specified +// intervals, regardless of the response's Cache-Control or Expires headers. +// +// By default this option is disabled. +func WithConstantInterval(d time.Duration) NewResourceOption { + return newResourceOption{option.New(identConstantInterval{}, d)} +} + +type AddOption interface { + option.Interface + newAddOption() +} + +type addOption struct { + option.Interface +} + +func (addOption) newAddOption() {} + +type identWaitReady struct{} + +// WithWaitReady specifies whether the client should wait for the resource to be +// ready before returning from the Add method. +// +// By default, the client will wait for the resource to be ready before returning. +// If you specify this option with a value of false, the client will not wait for +// the resource to be fully registered, which is usually not what you want. +// This option exists to accommodate for cases where you for some reason want to +// add a resource to the controller, but want to do something else before +// you wait for it. Make sure to call `r.Ready()` later on to ensure that +// the resource is ready before you try to access it. +func WithWaitReady(b bool) AddOption { + return addOption{option.New(identWaitReady{}, b)} +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/proxysink/proxysink.go b/vendor/github.com/lestrrat-go/httprc/v3/proxysink/proxysink.go new file mode 100644 index 0000000000..f290422d6c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/proxysink/proxysink.go @@ -0,0 +1,135 @@ +package proxysink + +import ( + "context" + "sync" +) + +type Backend[T any] interface { + Put(context.Context, T) +} + +// Proxy is used to send values through a channel. This is used to +// serialize calls to underlying sinks. +type Proxy[T any] struct { + mu *sync.Mutex + cancel context.CancelFunc + ch chan T + cond *sync.Cond + pending []T + backend Backend[T] + closed bool +} + +func New[T any](b Backend[T]) *Proxy[T] { + mu := &sync.Mutex{} + return &Proxy[T]{ + ch: make(chan T, 1), + mu: mu, + cond: sync.NewCond(mu), + backend: b, + cancel: func() {}, + } +} + +func (p *Proxy[T]) Run(ctx context.Context) { + defer p.cond.Broadcast() + + p.mu.Lock() + ctx, cancel := context.WithCancel(ctx) + p.cancel = cancel + p.mu.Unlock() + + go p.controlloop(ctx) + go p.flushloop(ctx) + + <-ctx.Done() +} + +func (p *Proxy[T]) controlloop(ctx context.Context) { + defer p.cond.Broadcast() + for { + select { + case <-ctx.Done(): + return + case r := <-p.ch: + p.mu.Lock() + p.pending = append(p.pending, r) + p.mu.Unlock() + } + p.cond.Broadcast() + } +} + +func (p *Proxy[T]) flushloop(ctx context.Context) { + const defaultPendingSize = 10 + pending := make([]T, defaultPendingSize) + for { + select { + case <-ctx.Done(): + p.mu.Lock() + if len(p.pending) <= 0 { + p.mu.Unlock() + return + } + default: + } + + p.mu.Lock() + for len(p.pending) <= 0 { + select { + case <-ctx.Done(): + p.mu.Unlock() + return + default: + p.cond.Wait() + } + } + + // extract all pending values, and clear the shared slice + if cap(pending) < len(p.pending) { + pending = make([]T, len(p.pending)) + } else { + pending = pending[:len(p.pending)] + } + copy(pending, p.pending) + if cap(p.pending) > defaultPendingSize { + p.pending = make([]T, 0, defaultPendingSize) + } else { + p.pending = p.pending[:0] + } + p.mu.Unlock() + + for _, v := range pending { + // send to sink serially + p.backend.Put(ctx, v) + } + } +} + +func (p *Proxy[T]) Put(ctx context.Context, v T) { + p.mu.Lock() + if p.closed { + p.mu.Unlock() + return + } + p.mu.Unlock() + + select { + case <-ctx.Done(): + return + case p.ch <- v: + return + } +} + +func (p *Proxy[T]) Close() { + p.mu.Lock() + defer p.mu.Unlock() + + if !p.closed { + p.closed = true + } + p.cancel() + p.cond.Broadcast() +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/resource.go b/vendor/github.com/lestrrat-go/httprc/v3/resource.go new file mode 100644 index 0000000000..e637f791fc --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/resource.go @@ -0,0 +1,359 @@ +package httprc + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "sync" + "sync/atomic" + "time" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/httpcc" + "github.com/lestrrat-go/httprc/v3/tracesink" +) + +// ResourceBase is a generic Resource type +type ResourceBase[T any] struct { + u string + ready chan struct{} // closed when the resource is ready (i.e. after first successful fetch) + once sync.Once + httpcl HTTPClient + t Transformer[T] + r atomic.Value + next atomic.Value + interval time.Duration + minInterval atomic.Int64 + maxInterval atomic.Int64 + busy atomic.Bool +} + +// NewResource creates a new Resource object which after fetching the +// resource from the URL, will transform the response body using the +// provided Transformer to an object of type T. +// +// This function will return an error if the URL is not a valid URL +// (i.e. it cannot be parsed by url.Parse), or if the transformer is nil. +func NewResource[T any](s string, transformer Transformer[T], options ...NewResourceOption) (*ResourceBase[T], error) { + var httpcl HTTPClient + var interval time.Duration + minInterval := DefaultMinInterval + maxInterval := DefaultMaxInterval + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identHTTPClient{}: + httpcl = option.Value().(HTTPClient) + case identMinimumInterval{}: + minInterval = option.Value().(time.Duration) + case identMaximumInterval{}: + maxInterval = option.Value().(time.Duration) + case identConstantInterval{}: + interval = option.Value().(time.Duration) + } + } + if transformer == nil { + return nil, fmt.Errorf(`httprc.NewResource: %w`, errTransformerRequired) + } + + if s == "" { + return nil, fmt.Errorf(`httprc.NewResource: %w`, errURLCannotBeEmpty) + } + + if _, err := url.Parse(s); err != nil { + return nil, fmt.Errorf(`httprc.NewResource: %w`, err) + } + r := &ResourceBase[T]{ + u: s, + httpcl: httpcl, + t: transformer, + interval: interval, + ready: make(chan struct{}), + } + if httpcl != nil { + r.httpcl = httpcl + } + r.minInterval.Store(int64(minInterval)) + r.maxInterval.Store(int64(maxInterval)) + r.SetNext(time.Unix(0, 0)) // initially, it should be fetched immediately + return r, nil +} + +// URL returns the URL of the resource. +func (r *ResourceBase[T]) URL() string { + return r.u +} + +// Ready returns an empty error when the resource is ready. If the context +// is canceled before the resource is ready, it will return the error from +// the context. +func (r *ResourceBase[T]) Ready(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-r.ready: + return nil + } +} + +// Get assigns the value of the resource to the provided pointer. +// If using the `httprc.ResourceBase[T]` type directly, you can use the `Resource()` +// method to get the resource directly. +// +// This method exists because parametric types cannot be assigned to a single object type +// that return different return values of the specialized type. i.e. for resources +// `ResourceBase[A]` and `ResourceBase[B]`, we cannot have a single interface that can +// be assigned to the same interface type `X` that expects a `Resource()` method that +// returns `A` or `B` depending on the type of the resource. When accessing the +// resource through the `httprc.Resource` interface, use this method to obtain the +// stored value. +func (r *ResourceBase[T]) Get(dst interface{}) error { + return blackmagic.AssignIfCompatible(dst, r.Resource()) +} + +// Resource returns the last fetched resource. If the resource has not been +// fetched yet, this will return the zero value of type T. +// +// If you would rather wait until the resource is fetched, you can use the +// `Ready()` method to wait until the resource is ready (i.e. fetched at least once). +func (r *ResourceBase[T]) Resource() T { + v := r.r.Load() + switch v := v.(type) { + case T: + return v + default: + var zero T + return zero + } +} + +func (r *ResourceBase[T]) Next() time.Time { + //nolint:forcetypeassert + return r.next.Load().(time.Time) +} + +func (r *ResourceBase[T]) SetNext(v time.Time) { + r.next.Store(v) +} + +func (r *ResourceBase[T]) ConstantInterval() time.Duration { + return r.interval +} + +func (r *ResourceBase[T]) MaxInterval() time.Duration { + return time.Duration(r.maxInterval.Load()) +} + +func (r *ResourceBase[T]) MinInterval() time.Duration { + return time.Duration(r.minInterval.Load()) +} + +func (r *ResourceBase[T]) SetMaxInterval(v time.Duration) { + r.maxInterval.Store(int64(v)) +} + +func (r *ResourceBase[T]) SetMinInterval(v time.Duration) { + r.minInterval.Store(int64(v)) +} + +func (r *ResourceBase[T]) SetBusy(v bool) { + r.busy.Store(v) +} + +func (r *ResourceBase[T]) IsBusy() bool { + return r.busy.Load() +} + +// limitedBody is a wrapper around an io.Reader that will only read up to +// MaxBufferSize bytes. This is provided to prevent the user from accidentally +// reading a huge response body into memory +type limitedBody struct { + rdr io.Reader + close func() error +} + +func (l *limitedBody) Read(p []byte) (n int, err error) { + return l.rdr.Read(p) +} + +func (l *limitedBody) Close() error { + return l.close() +} + +type traceSinkKey struct{} + +func withTraceSink(ctx context.Context, sink TraceSink) context.Context { + return context.WithValue(ctx, traceSinkKey{}, sink) +} + +func traceSinkFromContext(ctx context.Context) TraceSink { + if v := ctx.Value(traceSinkKey{}); v != nil { + //nolint:forcetypeassert + return v.(TraceSink) + } + return tracesink.Nop{} +} + +type httpClientKey struct{} + +func withHTTPClient(ctx context.Context, cl HTTPClient) context.Context { + return context.WithValue(ctx, httpClientKey{}, cl) +} + +func httpClientFromContext(ctx context.Context) HTTPClient { + if v := ctx.Value(httpClientKey{}); v != nil { + //nolint:forcetypeassert + return v.(HTTPClient) + } + return http.DefaultClient +} + +func (r *ResourceBase[T]) Sync(ctx context.Context) error { + traceSink := traceSinkFromContext(ctx) + httpcl := r.httpcl + if httpcl == nil { + httpcl = httpClientFromContext(ctx) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, r.u, nil) + if err != nil { + return fmt.Errorf(`httprc.Resource.Sync: failed to create request: %w`, err) + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: fetching %q", r.u)) + res, err := httpcl.Do(req) + if err != nil { + return fmt.Errorf(`httprc.Resource.Sync: failed to execute HTTP request: %w`, err) + } + defer res.Body.Close() + + next := r.calculateNextRefreshTime(ctx, res) + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: next refresh time for %q is %v", r.u, next)) + r.SetNext(next) + + if res.StatusCode != http.StatusOK { + return fmt.Errorf(`httprc.Resource.Sync: %w (status code=%d, url=%q)`, errUnexpectedStatusCode, res.StatusCode, r.u) + } + + // replace the body of the response with a limited reader that + // will only read up to MaxBufferSize bytes + res.Body = &limitedBody{ + rdr: &io.LimitedReader{R: res.Body, N: MaxBufferSize}, + close: res.Body.Close, + } + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: transforming %q", r.u)) + v, err := r.transform(ctx, res) + if err != nil { + return fmt.Errorf(`httprc.Resource.Sync: %w: %w`, errTransformerFailed, err) + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: storing new value for %q", r.u)) + r.r.Store(v) + r.once.Do(func() { close(r.ready) }) + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: stored value for %q", r.u)) + return nil +} + +func (r *ResourceBase[T]) transform(ctx context.Context, res *http.Response) (ret T, gerr error) { + // Protect the call to Transform with a defer/recover block, so that even + // if the Transform method panics, we can recover from it and return an error + defer func() { + if recovered := recover(); recovered != nil { + gerr = fmt.Errorf(`httprc.Resource.transform: %w: %v`, errRecoveredFromPanic, recovered) + } + }() + return r.t.Transform(ctx, res) +} + +func (r *ResourceBase[T]) determineNextFetchInterval(ctx context.Context, name string, fromHeader, minValue, maxValue time.Duration) time.Duration { + traceSink := traceSinkFromContext(ctx) + + if fromHeader > maxValue { + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s %s > maximum interval, using maximum interval %s", r.URL(), name, maxValue)) + return maxValue + } + + if fromHeader < minValue { + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s %s < minimum interval, using minimum interval %s", r.URL(), name, minValue)) + return minValue + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Using %s (%s)", r.URL(), name, fromHeader)) + return fromHeader +} + +func (r *ResourceBase[T]) calculateNextRefreshTime(ctx context.Context, res *http.Response) time.Time { + traceSink := traceSinkFromContext(ctx) + now := time.Now() + + // If constant interval is set, use that regardless of what the + // response headers say. + if interval := r.ConstantInterval(); interval > 0 { + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Explicit interval set, using value %s", r.URL(), interval)) + return now.Add(interval) + } + + if interval := r.extractCacheControlMaxAge(ctx, res); interval > 0 { + return now.Add(interval) + } + + if interval := r.extractExpiresInterval(ctx, res); interval > 0 { + return now.Add(interval) + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s No cache-control/expires headers found, using minimum interval", r.URL())) + return now.Add(r.MinInterval()) +} + +func (r *ResourceBase[T]) extractCacheControlMaxAge(ctx context.Context, res *http.Response) time.Duration { + traceSink := traceSinkFromContext(ctx) + + v := res.Header.Get(`Cache-Control`) + if v == "" { + return 0 + } + + dir, err := httpcc.ParseResponse(v) + if err != nil { + return 0 + } + + maxAge, ok := dir.MaxAge() + if !ok { + return 0 + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Cache-Control=max-age directive set (%d)", r.URL(), maxAge)) + return r.determineNextFetchInterval( + ctx, + "max-age", + time.Duration(maxAge)*time.Second, + r.MinInterval(), + r.MaxInterval(), + ) +} + +func (r *ResourceBase[T]) extractExpiresInterval(ctx context.Context, res *http.Response) time.Duration { + traceSink := traceSinkFromContext(ctx) + + v := res.Header.Get(`Expires`) + if v == "" { + return 0 + } + + expires, err := http.ParseTime(v) + if err != nil { + return 0 + } + + traceSink.Put(ctx, fmt.Sprintf("httprc.Resource.Sync: %s Expires header set (%s)", r.URL(), expires)) + return r.determineNextFetchInterval( + ctx, + "expires", + time.Until(expires), + r.MinInterval(), + r.MaxInterval(), + ) +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/tracesink/tracesink.go b/vendor/github.com/lestrrat-go/httprc/v3/tracesink/tracesink.go new file mode 100644 index 0000000000..b8400a94ae --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/tracesink/tracesink.go @@ -0,0 +1,52 @@ +package tracesink + +import ( + "context" + "log/slog" +) + +type Interface interface { + Put(context.Context, string) +} + +// Nop is an ErrorSink that does nothing. It does not require +// any initialization, so the zero value can be used. +type Nop struct{} + +// NewNop returns a new NopTraceSink object. The constructor +// is provided for consistency. +func NewNop() Interface { + return Nop{} +} + +// Put for NopTraceSink does nothing. +func (Nop) Put(context.Context, string) {} + +type slogSink struct { + level slog.Level + logger SlogLogger +} + +type SlogLogger interface { + Log(context.Context, slog.Level, string, ...any) +} + +// NewSlog returns a new ErrorSink that logs errors using the provided slog.Logger +func NewSlog(l SlogLogger) Interface { + return &slogSink{ + level: slog.LevelInfo, + logger: l, + } +} + +func (s *slogSink) Put(ctx context.Context, v string) { + s.logger.Log(ctx, s.level, v) +} + +// Func is a TraceSink that calls a function with the trace message. +type Func func(context.Context, string) + +// Put calls the function with the trace message. +func (f Func) Put(ctx context.Context, msg string) { + f(ctx, msg) +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/transformer.go b/vendor/github.com/lestrrat-go/httprc/v3/transformer.go new file mode 100644 index 0000000000..2bd0635a2c --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/transformer.go @@ -0,0 +1,37 @@ +package httprc + +import ( + "context" + "encoding/json" + "io" + "net/http" +) + +type bytesTransformer struct{} + +// BytesTransformer returns a Transformer that reads the entire response body +// as a byte slice. This is the default Transformer used by httprc.Client +func BytesTransformer() Transformer[[]byte] { + return bytesTransformer{} +} + +func (bytesTransformer) Transform(_ context.Context, res *http.Response) ([]byte, error) { + return io.ReadAll(res.Body) +} + +type jsonTransformer[T any] struct{} + +// JSONTransformer returns a Transformer that decodes the response body as JSON +// into the provided type T. +func JSONTransformer[T any]() Transformer[T] { + return jsonTransformer[T]{} +} + +func (jsonTransformer[T]) Transform(_ context.Context, res *http.Response) (T, error) { + var v T + if err := json.NewDecoder(res.Body).Decode(&v); err != nil { + var zero T + return zero, err + } + return v, nil +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/whitelist.go b/vendor/github.com/lestrrat-go/httprc/v3/whitelist.go new file mode 100644 index 0000000000..74ef2a1be6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/whitelist.go @@ -0,0 +1,113 @@ +package httprc + +import ( + "regexp" + "sync" +) + +// Whitelist is an interface that allows you to determine if a given URL is allowed +// or not. Implementations of this interface can be used to restrict the URLs that +// the client can access. +// +// By default all URLs are allowed, but this may not be ideal in production environments +// for security reasons. +// +// This exists because you might use this module to store resources provided by +// user of your application, in which case you cannot necessarily trust that the +// URLs are safe. +// +// You will HAVE to provide some sort of whitelist. +type Whitelist interface { + IsAllowed(string) bool +} + +// WhitelistFunc is a function type that implements the Whitelist interface. +type WhitelistFunc func(string) bool + +func (f WhitelistFunc) IsAllowed(u string) bool { return f(u) } + +// BlockAllWhitelist is a Whitelist implementation that blocks all URLs. +type BlockAllWhitelist struct{} + +// NewBlockAllWhitelist creates a new BlockAllWhitelist instance. It is safe to +// use the zero value of this type; this constructor is provided for consistency. +func NewBlockAllWhitelist() BlockAllWhitelist { return BlockAllWhitelist{} } + +func (BlockAllWhitelist) IsAllowed(_ string) bool { return false } + +// InsecureWhitelist is a Whitelist implementation that allows all URLs. Be careful +// when using this in your production code: make sure you do not blindly register +// URLs from untrusted sources. +type InsecureWhitelist struct{} + +// NewInsecureWhitelist creates a new InsecureWhitelist instance. It is safe to +// use the zero value of this type; this constructor is provided for consistency. +func NewInsecureWhitelist() InsecureWhitelist { return InsecureWhitelist{} } + +func (InsecureWhitelist) IsAllowed(_ string) bool { return true } + +// RegexpWhitelist is a jwk.Whitelist object comprised of a list of *regexp.Regexp +// objects. All entries in the list are tried until one matches. If none of the +// *regexp.Regexp objects match, then the URL is deemed unallowed. +type RegexpWhitelist struct { + mu sync.RWMutex + patterns []*regexp.Regexp +} + +// NewRegexpWhitelist creates a new RegexpWhitelist instance. It is safe to use the +// zero value of this type; this constructor is provided for consistency. +func NewRegexpWhitelist() *RegexpWhitelist { + return &RegexpWhitelist{} +} + +// Add adds a new regular expression to the list of expressions to match against. +func (w *RegexpWhitelist) Add(pat *regexp.Regexp) *RegexpWhitelist { + w.mu.Lock() + defer w.mu.Unlock() + w.patterns = append(w.patterns, pat) + return w +} + +// IsAllowed returns true if any of the patterns in the whitelist +// returns true. +func (w *RegexpWhitelist) IsAllowed(u string) bool { + w.mu.RLock() + patterns := w.patterns + w.mu.RUnlock() + for _, pat := range patterns { + if pat.MatchString(u) { + return true + } + } + return false +} + +// MapWhitelist is a jwk.Whitelist object comprised of a map of strings. +// If the URL exists in the map, then the URL is allowed to be fetched. +type MapWhitelist interface { + Whitelist + Add(string) MapWhitelist +} + +type mapWhitelist struct { + mu sync.RWMutex + store map[string]struct{} +} + +func NewMapWhitelist() MapWhitelist { + return &mapWhitelist{store: make(map[string]struct{})} +} + +func (w *mapWhitelist) Add(pat string) MapWhitelist { + w.mu.Lock() + defer w.mu.Unlock() + w.store[pat] = struct{}{} + return w +} + +func (w *mapWhitelist) IsAllowed(u string) bool { + w.mu.RLock() + _, b := w.store[u] + w.mu.RUnlock() + return b +} diff --git a/vendor/github.com/lestrrat-go/httprc/v3/worker.go b/vendor/github.com/lestrrat-go/httprc/v3/worker.go new file mode 100644 index 0000000000..57d7fb9624 --- /dev/null +++ b/vendor/github.com/lestrrat-go/httprc/v3/worker.go @@ -0,0 +1,60 @@ +package httprc + +import ( + "context" + "fmt" + "sync" +) + +type worker struct { + httpcl HTTPClient + incoming chan any + next <-chan Resource + nextsync <-chan synchronousRequest + errSink ErrorSink + traceSink TraceSink +} + +func (w worker) Run(ctx context.Context, readywg *sync.WaitGroup, donewg *sync.WaitGroup) { + w.traceSink.Put(ctx, "httprc worker: START worker loop") + defer w.traceSink.Put(ctx, "httprc worker: END worker loop") + defer donewg.Done() + ctx = withTraceSink(ctx, w.traceSink) + ctx = withHTTPClient(ctx, w.httpcl) + + readywg.Done() + for { + select { + case <-ctx.Done(): + w.traceSink.Put(ctx, "httprc worker: stopping worker loop") + return + case r := <-w.next: + w.traceSink.Put(ctx, fmt.Sprintf("httprc worker: syncing %q (async)", r.URL())) + if err := r.Sync(ctx); err != nil { + w.errSink.Put(ctx, err) + } + r.SetBusy(false) + + w.sendAdjustIntervalRequest(ctx, r) + case sr := <-w.nextsync: + w.traceSink.Put(ctx, fmt.Sprintf("httprc worker: syncing %q (synchronous)", sr.resource.URL())) + if err := sr.resource.Sync(ctx); err != nil { + sendReply(ctx, sr.reply, struct{}{}, err) + sr.resource.SetBusy(false) + return + } + sr.resource.SetBusy(false) + sendReply(ctx, sr.reply, struct{}{}, nil) + w.sendAdjustIntervalRequest(ctx, sr.resource) + } + } +} + +func (w worker) sendAdjustIntervalRequest(ctx context.Context, r Resource) { + w.traceSink.Put(ctx, "httprc worker: Sending interval adjustment request for "+r.URL()) + select { + case <-ctx.Done(): + case w.incoming <- adjustIntervalRequest{resource: r}: + } + w.traceSink.Put(ctx, "httprc worker: Sent interval adjustment request for "+r.URL()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.bazelignore b/vendor/github.com/lestrrat-go/jwx/v3/.bazelignore new file mode 100644 index 0000000000..50347e8777 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.bazelignore @@ -0,0 +1,4 @@ +cmd +bench +examples +tools diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.bazelrc b/vendor/github.com/lestrrat-go/jwx/v3/.bazelrc new file mode 100644 index 0000000000..b47648db7b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.bazelrc @@ -0,0 +1 @@ +import %workspace%/.aspect/bazelrc/bazel7.bazelrc diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.bazelversion b/vendor/github.com/lestrrat-go/jwx/v3/.bazelversion new file mode 100644 index 0000000000..56b6be4ebb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.bazelversion @@ -0,0 +1 @@ +8.3.1 diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.gitignore b/vendor/github.com/lestrrat-go/jwx/v3/.gitignore new file mode 100644 index 0000000000..c4c0ebff32 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.gitignore @@ -0,0 +1,39 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# IDE +.idea +.vscode +.DS_Store +*~ + +coverage.out + +# I redirect my test output to files named "out" way too often +out + +cmd/jwx/jwx + +bazel-* diff --git a/vendor/github.com/lestrrat-go/jwx/v3/.golangci.yml b/vendor/github.com/lestrrat-go/jwx/v3/.golangci.yml new file mode 100644 index 0000000000..214a9edaa8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/.golangci.yml @@ -0,0 +1,125 @@ +version: "2" +linters: + default: all + disable: + - cyclop + - depguard + - dupl + - err113 + - errorlint + - exhaustive + - funcorder + - funlen + - gochecknoglobals + - gochecknoinits + - gocognit + - gocritic + - gocyclo + - godot + - godox + - gosec + - gosmopolitan + - govet + - inamedparam + - ireturn + - lll + - maintidx + - makezero + - mnd + - nakedret + - nestif + - nlreturn + - noinlineerr + - nonamedreturns + - paralleltest + - perfsprint + - staticcheck + - recvcheck + - tagliatelle + - testifylint + - testpackage + - thelper + - varnamelen + - wrapcheck + - wsl + - wsl_v5 + settings: + govet: + disable: + - shadow + - fieldalignment + enable-all: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - staticcheck + path: /*.go + text: 'ST1003: should not use underscores in package names' + - linters: + - revive + path: /*.go + text: don't use an underscore in package name + - linters: + - staticcheck + text: SA1019 + - linters: + - contextcheck + - exhaustruct + path: /*.go + - linters: + - errcheck + path: /main.go + - linters: + - errcheck + path: internal/codegen/codegen.go + - linters: + - errcheck + - errchkjson + - forcetypeassert + path: internal/jwxtest/jwxtest.go + - linters: + - errcheck + - errchkjson + - forcetypeassert + path: /*_test.go + - linters: + - forbidigo + path: /*_example_test.go + - linters: + - forbidigo + path: cmd/jwx/jwx.go + - linters: + - revive + path: /*_test.go + text: 'var-naming: ' + - linters: + - revive + path: internal/tokens/jwe_tokens.go + text: "don't use ALL_CAPS in Go names" + - linters: + - revive + path: jwt/internal/types/ + text: "var-naming: avoid meaningless package names" + paths: + - third_party$ + - builtin$ + - examples$ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/lestrrat-go/jwx/v3/BUILD b/vendor/github.com/lestrrat-go/jwx/v3/BUILD new file mode 100644 index 0000000000..2759408882 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/BUILD @@ -0,0 +1,47 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") +load("@gazelle//:def.bzl", "gazelle") + +# gazelle:prefix github.com/lestrrat-go/jwx/v3 +# gazelle:go_naming_convention import_alias + +gazelle(name = "gazelle") + +go_library( + name = "jwx", + srcs = [ + "format.go", + "formatkind_string_gen.go", + "jwx.go", + "options.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3", + visibility = ["//visibility:public"], + deps = [ + "//internal/json", + "//internal/tokens", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwx_test", + srcs = ["jwx_test.go"], + deps = [ + ":jwx", + "//internal/jose", + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwe", + "//jwk", + "//jwk/ecdsa", + "//jws", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwx", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Changes b/vendor/github.com/lestrrat-go/jwx/v3/Changes new file mode 100644 index 0000000000..77381cf19d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Changes @@ -0,0 +1,208 @@ +Changes +======= + +v3 has many incompatibilities with v2. To see the full list of differences between +v2 and v3, please read the Changes-v3.md file (https://github.com/lestrrat-go/jwx/blob/develop/v3/Changes-v3.md) + +v3.0.10 04 Aug 2025 + * [jws/jwsbb] Add `jwsbb.ErrHeaderNotFound()` to return the same error type as when + a non-existent header is requested. via `HeaderGetXXX()` functions. Previously, this + function was called `jwsbb.ErrFieldNotFound()`, but it was a misnomer. + * [jws/jwsbb] Fix a bug where error return values from `HeaderGetXXX()` functions + could not be matched against `jwsbb.ErrHeaderNotFound()` using `errors.Is()`. + +v3.0.9 31 Jul 2025 + * [jws/jwsbb] `HeaderGetXXX()` functions now return errors when + the requested header is not found, or if the value cannot be + converted to the requested type. + + * [jwt] `(jwt.Token).Get` methods now return specific types of errors depending + on if a) the specified claim was not present, or b) the specified claim could + not be assigned to the destination variable. + + You can distinguish these by using `errors.Is` against `jwt.ClaimNotFoundError()` + or `jwt.ClaimAssignmentFailedError()` + +v3.0.8 27 Jun 2025 + * [jwe/jwebb] (EXPERIMENTAL) Add low-level functions for JWE operations. + * [jws/jwsbb] (EXPERIMENTAL/BREAKS COMPATIBILITY) Add io.Reader parameter + so your choice of source of randomness can be passed. Defaults to crypto/rand.Reader. + Function signatures around jwsbb.Sign() now accept an addition `rr io.Reader`, + which can be nil for 99% of use cases. + * [jws/jwsbb] Add HeaderParse([]byte), where it is expected that the header + is already in its base64 decoded format. + * misc: replace `interface{}` with `any` + +v3.0.7 16 Jun 2025 + * [jws/jwsbb] (EXPERIMENTAL) Add low-level fast access to JWS headers in compact + serialization form. + * [jws] Fix error reporting when no key matched for a signature. + * [jws] Refactor jws signer setup. + * Known algorithms are now implemented completely in the jws/jwsbb package. + * VerifierFor and SignerFor now always succeed, and will also return a Signer2 + or Verifier2 that wraps the legacy Signer or Verifier if one is registered. + +v3.0.6 13 Jun 2025 + * This release contains various performance improvements all over the code. + No, this time for real. In particular, the most common case for signing + a JWT with a key is approx 70% more efficient based on the number of allocations. + + Please read the entry for the (retracted) v3.0.4 for what else I have to + say about performance improvements + + * [jwt] Added fast-path for token signing and verification. The fast path + is triggered if you only pass `jwt.Sign()` and `jwt.Parse()` one options each + (`jwt.WithKey()`), with no suboptions. + + * [jws] Major refactoring around basic operations: + + * How to work with Signer/Verifier have completely changed. Please take + a look at examples/jws_custom_signer_verifier_example_test.go for how + to do it the new way. The old way still works, but it WILL be removed + when v4 arrives. + * Related to the above, old code has been moved to `jws/legacy`. + + * A new package `jws/jwsbb` has been added. `bb` stands for building blocks. + This package separates out the low-level JWS operations into its own + package. So if you are looking for just the signing of a payload with + a key, this is it. + + `jws/jwsbb` is currently considered to be EXPERIMENTAL. + +v3.0.5 11 Jun 2025 + * Retract v3.0.4 + * Code for v3.0.3 is the same as v3.0.3 + +v3.0.4 09 Jun 2025 + * This release contains various performance improvements all over the code. + + Because of the direction that this library is taking, we have always been + more focused on correctness and usability/flexibility over performance. + + It just so happens that I had a moment of inspiration and decided to see + just how good our AI-based coding agents are in this sort of analysis-heavy tasks. + + Long story short, the AI was fairly good at identifying suspicious code with + an okay accuracy, but completely failed to make any meaningful changes to the + code in a way that both did not break the code _and_ improved performance. + I am sure that they will get better in the near future, but for now, + I had to do the changes myself. I should clarify to their defence that + the AI was very helpful in writing cumbersome benchmark code for me. + + The end result is that we have anywhere from 10 to 30% performance improvements + in various parts of the code that we touched, based on number of allocations. + We believe that this would be a significant improvement for many users. + + For further improvements, we can see that there would be a clear benefit to + writing optimized code path that is designed to serve the most common cases. + For example, for the case of signing JWTs with a single key, we could provide + a path that skips a lot of extra processing (we kind of did that in this change, + but we _could_ go ever harder in this direction). However, it is a trade-off between + maintainability and performance, and as I am currently the sole maintainer of + this library for the time being, I only plan to pursue such a route where it + requires minimal effort on my part. + + If you are interested in helping out in this area, I hereby thank you in advance. + However, please be perfectly clear that unlike other types of changes, for performance + related changes, the balance between the performance gains and maintainability is + top priority. If you have good ideas and code, they will always be welcome, but + please be prepared to justify your changes. + + Finally, thank you for using this library! + +v3.0.3 06 Jun 2025 + * Update some dependencies + * [jwe] Change some error messages to contain more context information + +v3.0.2 03 Jun 2025 + * [transform] (EXPERIMENTAL) Add utility function `transform.AsMap` to convert a + Mappable object to a map[string]interface{}. This is useful for converting + objects such as `jws.Header`, `jwk.Key`, `jwt.Token`, etc. to a map that can + be used with other libraries that expect a map. + * [jwt] (EXPERIMENTAL) Added token filtering functionality through the TokenFilter interface. + * [jwt/openid] (EXPERIMENTAL) Added StandardClaimsFilter() for filtering standard OpenID claims. + * [jws] (EXPERIMENTAL) Added header filtering functionality through the HeaderFilter interface. + * [jwe] (EXPERIMENTAL) Added header filtering functionality through the HeaderFilter interface. + * [jwk] (EXPERIMENTAL) Added key filtering functionality through the KeyFilter interface. + * [jwk] `jwk.Export` previously did not recognize third-party objects that implemented `jwk.Key`, + as it was detecting what to do by checking if the object was one of our own unexported + types. This caused some problems for consumers of this library that wanted to extend the + features of the keys. + + Now `jwk.Export` checks types against interface types such as `jwk.RSAPrivateKey`, `jwk.ECDSAPrivateKey`, etc. + It also uses some reflect blackmagic to detect if the given object implements the `jwk.Key` interface + via embedding, so you should be able to embed a `jwk.Key` to another object to act as if it + is a legitimate `jwk.Key`, as far as `jwk.Export` is concerned. + +v3.0.1 29 Apr 2025 + * [jwe] Fixed a long standing bug that could lead to degraded encryption or failure to + decrypt JWE messages when a very specific combination of inputs were used for + JWE operations. + + This problem only manifested itself when the following conditions in content encryption or decryption + were met: + - Content encryption was specified to use DIRECT mode. + - Contentn encryption algorithm is specified as A256CBC_HS512 + - The key was erronously constructed with a 32-byte content encryption key (CEK) + + In this case, the user would be passing a mis-constructed key of 32-bytes instead + of the intended 64-bytes. In all other cases, this construction would cause + an error because `crypto/aes.NewCipher` would return an error when a key with length + not matching 16, 24, and 32 bytes is used. However, due to use using a the provided + 32-bytes as half CEK and half the hash, the `crypto/aes.NewCipher` was passed + a 16-byte key, which is fine for AES-128. So internally `crypto/aes.NewCipher` would + choose to use AES-128 instead of AES-256, and happily continue. Note that no other + key lengths such as 48 and 128 would have worked. It had to be exactly 32. + + This does indeed result in a downgraded encryption, but we believe it is unlikely that this would cause a problem in the real world, + as you would have to very specifically choose to use DIRECT mode, choose + the specific content encryption algorithm, AND also use the wrong key size of + exactly 32 bytes. + + However, in abandunce of caution, we recommend that you upgrade to v3.0.1 or later, + or v2.1.6 or later if you are still on v2 series. + + * [jws] Improve performance of jws.SplitCompact and jws.SplitCompactString + * [jwe] Improve performance of jwe.Parse + +v3.0.0 1 Apr 2025 + * Release initial v3.0.0 series. Code is identical to v3.0.0-beta2, except + for minor documentation changes. + + Please note that v1 will no longer be maintained. + + Going forward v2 will receive security updates but will no longer receive + feature updates. Users are encouraged to migrate to v3. There is no hard-set + guarantee as to how long v2 will be supported, but if/when v4 comes out, + v2 support will be terminated then. + +v3.0.0-beta2 30 Mar 2025 + * [jwk] Fix a bug where `jwk.Set`'s `Keys()` method did not return the proper + non-standard fields. (#1322) + * [jws][jwt] Implement `WithBase64Encoder()` options to pass base64 encoders + to use during signing/verifying signatures. This useful when the token + provider generates JWTs that don't follow the specification and uses base64 + encoding other than raw url encoding (no padding), such as, apparently, + AWS ALB. (#1324, #1328) + +v3.0.0-beta1 15 Mar 2025 + * [jwt] Token validation no longer truncates time based fields by default. + To restore old behavior, you can either change the global settings by + calling `jwt.Settings(jwt.WithTruncation(time.Second))`, or you can + change it by each invocation by using `jwt.Validate(..., jwt.WithTruncation(time.Second))` + +v3.0.0-alpha3 13 Mar 2025 + * [jwk] Importing/Exporting from jwk.Key with P256/P386/P521 curves to + ecdh.PrivateKey/ecdh.PublicKey should now work. Previously these keys were not properly + recognized by the exporter/importer. Note that keys that use X25519 and P256/P384/P521 + behave differently: X25519 keys can only be exported to/imported from OKP keys, + while P256/P384/P521 can be exported to either ecdsa or ecdh keys. + +v3.0.0-alpha2 25 Feb 2025 + * Update to work with go1.24 + * Update tests to work with latest latchset/jose + * Fix build pipeline to work with latest golangci-lint + * Require go1.23 + +v3.0.0-alpha1 01 Nov 2024 + * Initial release of v3 line. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Changes-v2.md b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v2.md new file mode 100644 index 0000000000..af146ed33a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v2.md @@ -0,0 +1,390 @@ +# Incompatible Changes from v1 to v2 + +These are changes that are incompatible with the v1.x.x version. + +* [tl;dr](#tldr) - If you don't feel like reading the details -- but you will read the details, right? +* [Detailed List of Changes](#detailed-list-of-changes) - A comprehensive list of changes from v1 to v2 + +# tl;dr + +## JWT + +```go +// most basic +jwt.Parse(serialized, jwt.WithKey(alg, key)) // NOTE: verification and validation are ENABLED by default! +jwt.Sign(token, jwt.WithKey(alg,key)) + +// with a jwk.Set +jwt.Parse(serialized, jwt.WithKeySet(set)) + +// UseDefault/InferAlgorithm with JWKS +jwt.Parse(serialized, jwt.WithKeySet(set, + jws.WithUseDefault(true), jws.WithInferAlgorithm(true)) + +// Use `jku` +jwt.Parse(serialized, jwt.WithVerifyAuto(...)) + +// Any other custom key provisioning (using functions in this +// example, but can be anything that fulfills jws.KeyProvider) +jwt.Parse(serialized, jwt.WithKeyProvider(jws.KeyProviderFunc(...))) +``` + +## JWK + +```go +// jwk.New() was confusing. Renamed to fit the actual implementation +key, err := jwk.FromRaw(rawKey) + +// Algorithm() now returns jwa.KeyAlgorithm type. `jws.Sign()` +// and other function that receive JWK algorithm names accept +// this new type, so you can use the same key and do the following +// (previously you needed to type assert) +jws.Sign(payload, jws.WithKey(key.Algorithm(), key)) + +// If you need the specific type, type assert +key.Algorithm().(jwa.SignatureAlgorithm) + +// jwk.AutoRefresh is no more. Use jwk.Cache +cache := jwk.NewCache(ctx, options...) + +// Certificate chains are no longer jwk.CertificateChain type, but +// *(github.com/lestrrat-go/jwx/cert).Chain +cc := key.X509CertChain() // this is *cert.Chain now +``` + +## JWS + +```go +// basic +jws.Sign(payload, jws.WithKey(alg, key)) +jws.Sign(payload, jws.WithKey(alg, key), jws.WithKey(alg, key), jws.WithJSON(true)) +jws.Verify(signed, jws.WithKey(alg, key)) + +// other ways to pass the key +jws.Sign(payload, jws.WithKeySet(jwks)) +jws.Sign(payload, jws.WithKeyProvider(kp)) + +// retrieve the key that succeeded in verifying +var keyUsed interface{} +jws.Verify(signed, jws.WithKeySet(jwks), jws.WithKeyUsed(&keyUsed)) +``` + +## JWE + +```go +// basic +jwe.Encrypt(payload, jwe.WithKey(alg, key)) // other defaults are inferred +jwe.Encrypt(payload, jwe.WithKey(alg, key), jwe.WithKey(alg, key), jwe.WithJSON(true)) +jwe.Decrypt(encrypted, jwe.WithKey(alg, key)) + +// other ways to pass the key +jwe.Encrypt(payload, jwe.WithKeySet(jwks)) +jwe.Encrypt(payload, jwe.WithKeyProvider(kp)) + +// retrieve the key that succeeded in decrypting +var keyUsed interface{} +jwe.Verify(signed, jwe.WithKeySet(jwks), jwe.WithKeyUsed(&keyUsed)) +``` + +# Detailed List of Changes + +## Module + +* Module now requires go 1.16 + +* Use of github.com/pkg/errors is no more. If you were relying on behavior + that depends on the errors being an instance of github.com/pkg/errors + then you need to change your code + +* File-generation tools have been moved out of internal/ directories. + These files pre-dates Go modules, and they were in internal/ in order + to avoid being listed in the `go doc` -- however, now that we can + make them separate modules this is no longer necessary. + +* New package `cert` has been added to handle `x5c` certificate + chains, and to work with certificates + * cert.Chain to store base64 encoded ASN.1 DER format certificates + * cert.EncodeBase64 to encode ASN.1 DER format certificate using base64 + * cert.Create to create a base64 encoded ASN.1 DER format certificates + * cert.Parse to parse base64 encoded ASN.1 DER format certificates + +## JWE + +* `jwe.Compact()`'s signature has changed to + `jwe.Compact(*jwe.Message, ...jwe.CompactOption)` + +* `jwe.JSON()` has been removed. You can generate JSON serialization + using `jwe.Encrypt(jwe.WitJSON())` or `json.Marshal(jwe.Message)` + +* `(jwe.Message).Decrypt()` has been removed. Since formatting of the + original serialized message matters (including whitespace), using a parsed + object was inherently confusing. + +* `jwe.Encrypt()` can now generate JWE messages in either compact or JSON + forms. By default, the compact form is used. JSON format can be + enabled by using the `jwe.WithJSON` option. + +* `jwe.Encrypt()` can now accept multiple keys by passing multiple + `jwe.WithKey()` options. This can be used with `jwe.WithJSON` to + create JWE messages with multiple recipients. + +* `jwe.DecryptEncryptOption()` has been renamed to `jwe.EncryptDecryptOption()`. + This is so that it is more uniform with `jws` equivalent of `jws.SignVerifyOption()` + where the producer (`Sign`) comes before the consumer (`Verify`) in the naming + +* `jwe.WithCompact` and `jwe.WithJSON` options have been added + to control the serialization format. + +* jwe.Decrypt()'s method signature has been changed to `jwt.Decrypt([]byte, ...jwe.DecryptOption) ([]byte, error)`. + These options can be stacked. Therefore, you could configure the + verification process to attempt a static key pair, a JWKS, and only + try other forms if the first two fails, for example. + + - For static key pair, use `jwe.WithKey()` + - For static JWKS, use `jwe.WithKeySet()` (NOTE: InferAlgorithmFromKey like in `jws` package is NOT supported) + - For custom, possibly dynamic key provisioning, use `jwe.WithKeyProvider()` + +* jwe.Decrypter has been unexported. Users did not need this. + +* jwe.WithKeyProvider() has been added to specify arbitrary + code to specify which keys to try. + +* jwe.KeyProvider interface has been added + +* jwe.KeyProviderFunc has been added + +* `WithPostParser()` has been removed. You can achieve the same effect + by using `jwe.WithKeyProvider()`. Because this was the only consumer for + `jwe.DecryptCtx`, this type has been removed as well. + +* `x5c` field type has been changed to `*cert.Chain` instead of `[]string` + +* Method signature for `jwe.Parse()` has been changed to include options, + but options are currently not used + +* `jwe.ReadFile` now supports the option `jwe.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +* jwe.WithKeyUsed has been added to allow users to retrieve + the key used for decryption. This is useful in cases you provided + multiple keys and you want to know which one was successful + +## JWK + +* `jwk.New()` has been renamed to `jwk.FromRaw()`, which hopefully will + make it easier for the users what the input should be. + +* `jwk.Set` has many interface changes: + * Changed methods to match jwk.Key and its semantics: + * Field is now Get() (returns values for arbitrary fields other than keys). Fetching a key is done via Key() + * Remove() now removes arbitrary fields, not keys. to remove keys, use RemoveKey() + * Iterate has been added to iterate through all non-key fields. + * Add is now AddKey(Key) string, and returns an error when the same key is added + * Get is now Key(int) (Key, bool) + * Remove is now RemoveKey(Key) error + * Iterate is now Keys(context.Context) KeyIterator + * Clear is now Clear() error + +* `jwk.CachedSet` has been added. You can create a `jwk.Set` that is backed by + `jwk.Cache` so you can do this: + +```go +cache := jkw.NewCache(ctx) +cachedSet := jwk.NewCachedSet(cache, jwksURI) + +// cachedSet is always the refreshed, cached version from jwk.Cache +jws.Verify(signed, jws.WithKeySet(cachedSet)) +``` + +* `jwk.NewRSAPRivateKey()`, `jwk.NewECDSAPrivateKey()`, etc have been removed. + There is no longer any way to create concrete types of `jwk.Key` + +* `jwk.Key` type no longer supports direct unmarshaling via `json.Unmarshal()`, + because you can no longer instantiate concrete `jwk.Key` types. You will need to + use `jwk.ParseKey()`. See the documentation for ways to parse JWKs. + +* `(jwk.Key).Algorithm()` is now of `jwk.KeyAlgorithm` type. This field used + to be `string` and therefore could not be passed directly to `jwt.Sign()` + `jws.Sign()`, `jwe.Encrypt()`, et al. This is no longer the case, and + now you can pass it directly. See + https://github.com/lestrrat-go/jwx/blob/v2/docs/99-faq.md#why-is-jwkkeyalgorithm-and-jwakeyalgorithm-so-confusing + for more details + +* `jwk.Fetcher` and `jwk.FetchFunc` has been added. + They represent something that can fetch a `jwk.Set` + +* `jwk.CertificateChain` has been removed, use `*cert.Chain` +* `x5c` field type has been changed to `*cert.Chain` instead of `[]*x509.Certificate` + +* `jwk.ReadFile` now supports the option `jwk.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +* Added `jwk.PostFetcher`, `jwk.PostFetchFunc`, and `jwk.WithPostFetch` to + allow users to get at the `jwk.Set` that was fetched in `jwk.Cache`. + This will make it possible for users to supply extra information and edit + `jwk.Set` after it has been fetched and parsed, but before it is cached. + You could, for example, modify the `alg` field so that it's easier to + work with when you use it in `jws.Verify` later. + +* Reworked `jwk.AutoRefresh` in terms of `github.com/lestrrat-go/httprc` + and renamed it `jwk.Cache`. + + Major difference between `jwk.AutoRefresh` and `jwk.Cache` is that while + former used one `time.Timer` per resource, the latter uses a static timer + (based on `jwk.WithRefreshWindow()` value, default 15 minutes) that periodically + refreshes all resources that were due to be refreshed within that time frame. + + This method may cause your updates to happen slightly later, but uses significantly + less resources and is less prone to clogging. + +* Reimplemented `jwk.Fetch` in terms of `github.com/lestrrat-go/httprc`. + +* Previously `jwk.Fetch` and `jwk.AutoRefresh` respected backoff options, + but this has been removed. This is to avoid unwanted clogging of the fetch workers + which is the default processing mode in `github.com/lestrrat-go/httprc`. + + If you are using backoffs, you need to control your inputs more carefully so as + not to clog your fetch queue, and therefore you should be writing custom code that + suits your needs + +## JWS + +* `jws.Sign()` can now generate JWS messages in either compact or JSON + forms. By default, the compact form is used. JSON format can be + enabled by using the `jws.WithJSON` option. + +* `jws.Sign()` can now accept multiple keys by passing multiple + `jws.WithKey()` options. This can be used with `jws.WithJSON` to + create JWS messages with multiple signatures. + +* `jws.WithCompact` and `jws.WithJSON` options have been added + to control the serialization format. + +* jws.Verify()'s method signature has been changed to `jwt.Verify([]byte, ...jws.VerifyOption) ([]byte, error)`. + These options can be stacked. Therefore, you could configure the + verification process to attempt a static key pair, a JWKS, and only + try other forms if the first two fails, for example. + + - For static key pair, use `jws.WithKey()` + - For static JWKS, use `jws.WithKeySet()` + - For enabling verification using `jku`, use `jws.WithVerifyAuto()` + - For custom, possibly dynamic key provisioning, use `jws.WithKeyProvider()` + +* jws.WithVerify() has been removed. + +* jws.WithKey() has been added to specify an algorithm + key to + verify the payload with. + +* jws.WithKeySet() has been added to specify a JWKS to be used for + verification. By default `kid` AND `alg` must match between the signature + and the key. + + The option can take further suboptions: + +```go +jws.Parse(serialized, + jws.WithKeySet(set, + // by default `kid` is required. set false to disable. + jws.WithRequireKid(false), + // optionally skip matching kid if there's exactly one key in set + jws.WithUseDefault(true), + // infer algorithm name from key type + jws.WithInferAlgorithm(true), + ), +) +``` + +* `jws.VerifuAuto` has been removed in favor of using + `jws.WithVerifyAuto` option with `jws.Verify()` + +* `jws.WithVerifyAuto` has been added to enable verification + using `jku`. + + The first argument must be a jwk.Fetcher object, but can be + set to `nil` to use the default implementation which is `jwk.Fetch` + + The rest of the arguments are treated as options passed to the + `(jwk.Fetcher).Fetch()` function. + +* Remove `jws.WithPayloadSigner()`. This should be completely replaceable + using `jws.WithKey()` + +* jws.WithKeyProvider() has been added to specify arbitrary + code to specify which keys to try. + +* jws.KeyProvider interface has been added + +* jws.KeyProviderFunc has been added + +* jws.WithKeyUsed has been added to allow users to retrieve + the key used for verification. This is useful in cases you provided + multiple keys and you want to know which one was successful + +* `x5c` field type has been changed to `*cert.Chain` instead of `[]string` + +* `jws.ReadFile` now supports the option `jws.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +## JWT + +* `jwt.Parse` now verifies the signature and validates the token + by default. You must disable it explicitly using `jwt.WithValidate(false)` + and/or `jwt.WithVerify(false)` if you only want to parse the JWT message. + + If you don't want either, a convenience function `jwt.ParseInsecure` + has been added. + +* `jwt.Parse` can only parse raw JWT (JSON) or JWS (JSON or Compact). + It no longer accepts JWE messages. + +* `jwt.WithDecrypt` has been removed + +* `jwt.WithJweHeaders` has been removed + +* `jwt.WithVerify()` has been renamed to `jwt.WithKey()`. The option can + be used for signing, encryption, and parsing. + +* `jwt.Validator` has been changed to return `jwt.ValidationError`. + If you provide a custom validator, you should wrap the error with + `jwt.NewValidationError()` + +* `jwt.UseDefault()` has been removed. You should use `jws.WithUseDefault()` + as a suboption in the `jwt.WithKeySet()` option. + +```go +jwt.Parse(serialized, jwt.WithKeySet(set, jws.WithUseDefault(true))) +``` + +* `jwt.InferAlgorithmFromKey()` has been removed. You should use + `jws.WithInferAlgorithmFromKey()` as a suboption in the `jwt.WithKeySet()` option. + +```go +jwt.Parse(serialized, jwt.WithKeySet(set, jws.WithInferAlgorithmFromKey(true))) +``` + +* jwt.WithKeySetProvider has been removed. Use `jwt.WithKeyProvider()` + instead. If jwt.WithKeyProvider seems a bit complicated, use a combination of + JWS parse, no-verify/validate JWT parse, and an extra JWS verify: + +```go +msg, _ := jws.Parse(signed) +token, _ := jwt.Parse(msg.Payload(), jwt.WithVerify(false), jwt.WithValidate(false)) +// Get information out of token, for example, `iss` +switch token.Issuer() { +case ...: + jws.Verify(signed, jwt.WithKey(...)) +} +``` + +* `jwt.WithHeaders` and `jwt.WithJwsHeaders` have been removed. + You should be able to use the new `jwt.WithKey` option to pass headers + +* `jwt.WithSignOption` and `jwt.WithEncryptOption` have been added as + escape hatches for options that are declared in `jws` and `jwe` packages + but not in `jwt` + +* `jwt.ReadFile` now supports the option `jwt.WithFS` which allows you to + read data from arbitrary `fs.FS` objects + +* `jwt.Sign()` has been changed so that it works more like the new `jws.Sign()` + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Changes-v3.md b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v3.md new file mode 100644 index 0000000000..c2fa8747b9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Changes-v3.md @@ -0,0 +1,140 @@ +# Incompatible Changes from v2 to v3 + +These are changes that are incompatible with the v2.x.x version. + +# Detailed list of changes + +## Module + +* This module now requires Go 1.23 + +* All `xxx.Get()` methods have been changed from `Get(string) (interface{}, error)` to + `Get(string, interface{}) error`, where the second argument should be a pointer + to the storage destination of the field. + +* All convenience accessors (e.g. `(jwt.Token).Subject`) now return `(T, bool)` instead of + `T`. If you want an accessor that returns a single value, consider using `Get()` + +* Most major errors can now be differentiated using `errors.Is` + +## JWA + +* All string constants have been renamed to equivalent functions that return a struct. + You should rewrite `jwa.RS256` as `jwa.RS256()` and so forth. + +* By default, only known algorithm names are accepted. For example, in our JWK tests, + there are tests that deal with "ECMR" algorithm, but this will now fail by default. + If you want this algorithm to succeed parsing, you need to call `jwa.RegisterXXXX` + functions before using them. + +* Previously, unmarshaling unquoted strings used to work (e.g. `var s = "RS256"`), + but now they must conform to the JSON standard and be quoted (e.g. `var s = strconv.Quote("RS256")`) + +## JWT + +* All convenience accessors (e.g. `Subject`) now return `(T, bool)` instead of + just `T`. If you want a single return value accessor, use `Get(dst) error` instead. + +* Validation used to work for `iat`, `nbf`, `exp` fields where these fields were + set to the explicit time.Time{} zero value, but now the _presence_ of these fields matter. + +* Validation of fields related to time used to be truncated to one second accuracy, + but no longer does so. To restore old behavior, you can either change the global settings by + calling `jwt.Settings(jwt.WithTruncation(time.Second))`, or you can + change it by each invocation by using `jwt.Validate(..., jwt.WithTruncation(time.Second))` + +* Error names have been renamed. For example `jwt.ErrInvalidJWT` has been renamed to + `jwt.UnknownPayloadTypeError` to better reflect what the error means. For other errors, + `func ErrXXXX()` have generally been renamed to `func XXXError()` + +* Validation errors are now wrapped. While `Validate()` returns a `ValidateError()` type, + it can also be matched against more specific error types such as `TokenExpierdError()` + using `errors.Is` + +* `jwt.ErrMissingRequiredClaim` has been removed + +## JWS + +* Iterators have been completely removed. +* As a side effect of removing iterators, some methods such as `Copy()` lost the + `context.Context` argument + +* All convenience accessors (e.g. `Algorithm`) now return `(T, bool)` instead of + just `T`. If you want a single return value accessor, use `Get(dst) error` instead. + +* Errors from `jws.Sign` and `jws.Verify`, as well as `jws.Parse` (and friends) + can now be differentiated by using `errors.Is`. All `jws.IsXXXXError` functions + have been removed. + +## JWE + +* Iterators have been completely removed. +* As a side effect of removing iterators, some methods such as `Copy()` lost the + `context.Context` argument + +* All convenience accessors (e.g. `Algorithm`) now return `(T, bool)` instead of + just `T`. If you want a single return value accessor, use `Get(dst) error` instead. + +* Errors from `jwe.Decrypt` and `jwe.Encrypt`, as well as `jwe.Parse` (and friends) + can now be differentiated by using `errors.Is`. All `jwe.IsXXXXrror` functions + have been removed. + +## JWK + +* All convenience accessors (e.g. `Algorithm`, `Crv`) now return `(T, bool)` instead + of just `T`, except `KeyType`, which _always_ returns a valid value. If you want a + single return value accessor, use `Get(dst) error` instead. + +* `jwk.KeyUsageType` can now be configured so that it's possible to assign values + other than "sig" and "enc" via `jwk.RegisterKeyUsage()`. Furthermore, strict + checks can be turned on/off against these registered values + +* `jwk.Cache` has been completely re-worked based on github.com/lestrrat-go/httprc/v3. + In particular, the default whitelist mode has changed from "block everything" to + "allow everything". + +* Experimental secp256k1 encoding/decoding for PEM encoded ASN.1 DER Format + has been removed. Instead, `jwk.PEMDecoder` and `jwk.PEMEncoder` have been + added to support those who want to perform non-standard PEM encoding/decoding + +* Iterators have been completely removed. + +* `jwk/x25519` has been removed. To use X25519 keys, use `(crypto/ecdh).PrivateKey` and + `(crypto/ecdh).PublicKey`. Similarly, internals have been reworked to use `crypto/ecdh` + +* Parsing has completely been reworked. It is now possible to add your own `jwk.KeyParser` + to generate a custom `jwk.Key` that this library may not natively support. Also see + `jwk.RegisterKeyParser()` + +* `jwk.KeyProbe` has been added to aid probing the JSON message. This is used to + guess the type of key described in the JSON message before deciding which concrete + type to instantiate, and aids implementing your own `jwk.KeyParser`. Also see + `jwk.RegisterKeyProbe()` + +* Conversion between raw keys and `jwk.Key` can be customized using `jwk.KeyImporter` and `jwk.KeyExporter`. + Also see `jwk.RegisterKeyImporter()` and `jwk.RegisterKeyExporter()` + +* Added `jwk/ecdsa` to keep track of which curves are available for ECDSA keys. + +* `(jwk.Key).Raw()` has been deprecated. Use `jwk.Export()` instead to convert `jwk.Key` + objects into their "raw" versions (e.g. `*rsa.PrivateKey`, `*ecdsa.PrivateKey`, etc). + This is to allow third parties to register custom key types that this library does not + natively support: Whereas a method must be bound to an object, and thus does not necessarily + have a way to hook into a global settings (i.e. custom exporter/importer) for arbitrary + key types, if the entrypoint is a function it's much easier and cleaner to for third-parties + to take advantage and hook into the mechanisms. + +* `jwk.FromRaw()` has been derepcated. Use `jwk.Import()` instead to convert "raw" + keys (e.g. `*rsa.PrivateKEy`, `*Ecdsa.PrivateKey`, etc) int `jwk.Key`s. + +* `(jwk.Key).FromRaw()` has been deprecated. The method `(jwk.Key).Import()` still exist for + built-in types, but it is no longer part of any public API (`interface{}`). + +* `jwk.Fetch` is marked as a simple wrapper around `net/http` and `jwk.Parse`. + +* `jwk.SetGlobalFetcher` has been deprecated. + +* `jwk.Fetcher` has been clearly marked as something that has limited + usage for `jws.WithVerifyAuto` + +* `jwk.Key` with P256/P386/P521 curves can be exporrted to `ecdh.PrivateKey`/`ecdh.PublicKey` \ No newline at end of file diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/LICENSE b/vendor/github.com/lestrrat-go/jwx/v3/LICENSE similarity index 99% rename from vendor/github.com/open-policy-agent/opa/internal/jwx/LICENSE rename to vendor/github.com/lestrrat-go/jwx/v3/LICENSE index 6369f4fcc4..205e33a7f1 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/LICENSE +++ b/vendor/github.com/lestrrat-go/jwx/v3/LICENSE @@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel new file mode 100644 index 0000000000..004fb2a9a2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel @@ -0,0 +1,32 @@ +module( + name = "com_github_lestrrat_go_jwx_v3", + version = "3.0.0", + repo_name = "com_github_lestrrat_go_jwx_v2", +) + +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "rules_go", version = "0.55.1") +bazel_dep(name = "gazelle", version = "0.44.0") +bazel_dep(name = "aspect_bazel_lib", version = "2.11.0") + +# Go SDK setup - using Go 1.23.6 to match the toolchain in go.mod +go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +go_sdk.download(version = "1.23.6") + +# Go dependencies from go.mod +go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") +go_deps.from_file(go_mod = "//:go.mod") + +# Use repositories for external Go dependencies +use_repo( + go_deps, + "com_github_decred_dcrd_dcrec_secp256k1_v4", + "com_github_goccy_go_json", + "com_github_lestrrat_go_blackmagic", + "com_github_lestrrat_go_httprc_v3", + "com_github_lestrrat_go_option_v2", + "com_github_segmentio_asm", + "com_github_stretchr_testify", + "com_github_valyala_fastjson", + "org_golang_x_crypto", +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel.lock b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel.lock new file mode 100644 index 0000000000..2848e8716d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/MODULE.bazel.lock @@ -0,0 +1,230 @@ +{ + "lockFileVersion": 18, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "cb1ba9f9999ed0bc08600c221f532c1ddd8d217686b32ba7d45b0713b5131452", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/source.json": "92494d5aa43b96665397dd13ee16023097470fa85e276b93674d62a244de47ee", + "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8", + "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", + "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", + "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", + "https://bcr.bazel.build/modules/gazelle/0.44.0/MODULE.bazel": "fd3177ca0938da57a1e416cad3f39b9c4334defbc717e89aba9d9ddbbb0341da", + "https://bcr.bazel.build/modules/gazelle/0.44.0/source.json": "7fb65ef9c1ce470d099ca27fd478673d9d64c844af28d0d472b0874c7d590cb6", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/MODULE.bazel": "fb8d25550742674d63d7b250063d4580ca530499f045d70748b1b142081ebb92", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/source.json": "e53a759a72488d2c0576f57491ef2da0cf4aab05ac0997314012495935531b73", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", + "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2.bcr.1/MODULE.bazel": "52f4126f63a2f0bbf36b99c2a87648f08467a4eaf92ba726bc7d6a500bbf770c", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8", + "https://bcr.bazel.build/modules/rules_go/0.42.0/MODULE.bazel": "8cfa875b9aa8c6fce2b2e5925e73c1388173ea3c32a0db4d2b4804b453c14270", + "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd", + "https://bcr.bazel.build/modules/rules_go/0.51.0/MODULE.bazel": "b6920f505935bfd69381651c942496d99b16e2a12f3dd5263b90ded16f3b4d0f", + "https://bcr.bazel.build/modules/rules_go/0.55.1/MODULE.bazel": "a57a6fc59a74326c0b440d07cca209edf13c7d1a641e48cfbeab56e79f873609", + "https://bcr.bazel.build/modules/rules_go/0.55.1/source.json": "827a740c8959c9d20616889e7746cde4dcc6ee80d25146943627ccea0736328f", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.12.0/MODULE.bazel": "8e6590b961f2defdfc2811c089c75716cb2f06c8a4edeb9a8d85eaa64ee2a761", + "https://bcr.bazel.build/modules/rules_java/8.12.0/source.json": "cbd5d55d9d38d4008a7d00bee5b5a5a4b6031fcd4a56515c9accbcd42c7be2ba", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": "939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.1/source.json": "b6500ffcd7b48cd72c29bb67bcac781e12701cc0d6d55d266a652583cfcdab01", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "hUTp2w+RUVdL7ma5esCXZJAFnX7vLbVfLd7FwnQI6bU=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin+", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/Makefile b/vendor/github.com/lestrrat-go/jwx/v3/Makefile new file mode 100644 index 0000000000..672c007b29 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/Makefile @@ -0,0 +1,98 @@ +.PHONY: generate realclean cover viewcover test lint check_diffs imports tidy jwx +generate: + @go generate + @$(MAKE) generate-jwa generate-jwe generate-jwk generate-jws generate-jwt + @./tools/cmd/gofmt.sh + +generate-%: + @go generate $(shell pwd -P)/$(patsubst generate-%,%,$@) + +realclean: + rm coverage.out + +test-cmd: + env TESTOPTS="$(TESTOPTS)" ./tools/test.sh + +test: + $(MAKE) test-stdlib TESTOPTS= + +test-stdlib: + $(MAKE) test-cmd TESTOPTS= + +test-goccy: + $(MAKE) test-cmd TESTOPTS="-tags jwx_goccy" + +test-es256k: + $(MAKE) test-cmd TESTOPTS="-tags jwx_es256k" + +test-secp256k1-pem: + $(MAKE) test-cmd TESTOPTS="-tags jwx_es256k,jwx_secp256k1_pem" + +test-asmbase64: + $(MAKE) test-cmd TESTOPTS="-tags jwx_asmbase64" + +test-alltags: + $(MAKE) test-cmd TESTOPTS="-tags jwx_asmbase64,jwx_goccy,jwx_es256k,jwx_secp256k1_pem" + +cover-cmd: + env MODE=cover ./tools/test.sh + +cover: + $(MAKE) cover-stdlib + +cover-stdlib: + $(MAKE) cover-cmd TESTOPTS= + +cover-goccy: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_goccy" + +cover-es256k: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_es256k" + +cover-secp256k1-pem: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_es256k,jwx_secp256k1" + +cover-asmbase64: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_asmbase64" + +cover-alltags: + $(MAKE) cover-cmd TESTOPTS="-tags jwx_asmbase64,jwx_goccy,jwx_es256k,jwx_secp256k1_pem" + +smoke-cmd: + env MODE=short ./tools/test.sh + +smoke: + $(MAKE) smoke-stdlib + +smoke-stdlib: + $(MAKE) smoke-cmd TESTOPTS= + +smoke-goccy: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_goccy" + +smoke-es256k: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_es256k" + +smoke-secp256k1-pem: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_es256k,jwx_secp256k1_pem" + +smoke-alltags: + $(MAKE) smoke-cmd TESTOPTS="-tags jwx_goccy,jwx_es256k,jwx_secp256k1_pem" + +viewcover: + go tool cover -html=coverage.out + +lint: + golangci-lint run ./... + +check_diffs: + ./scripts/check-diff.sh + +imports: + goimports -w ./ + +tidy: + ./scripts/tidy.sh + +jwx: + @./tools/cmd/install-jwx.sh diff --git a/vendor/github.com/lestrrat-go/jwx/v3/README.md b/vendor/github.com/lestrrat-go/jwx/v3/README.md new file mode 100644 index 0000000000..632033f3cb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/README.md @@ -0,0 +1,263 @@ +# github.com/lestrrat-go/jwx/v3 [![CI](https://github.com/lestrrat-go/jwx/actions/workflows/ci.yml/badge.svg)](https://github.com/lestrrat-go/jwx/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3) [![codecov.io](https://codecov.io/github/lestrrat-go/jwx/coverage.svg?branch=v3)](https://codecov.io/github/lestrrat-go/jwx?branch=v3) + +Go module implementing various JWx (JWA/JWE/JWK/JWS/JWT, otherwise known as JOSE) technologies. + +If you are using this module in your product or your company, please add your product and/or company name in the [Wiki](https://github.com/lestrrat-go/jwx/wiki/Users)! It really helps keeping up our motivation. + +# Features + +* Complete coverage of JWA/JWE/JWK/JWS/JWT, not just JWT+minimum tool set. + * Supports JWS messages with multiple signatures, both compact and JSON serialization + * Supports JWS with detached payload + * Supports JWS with unencoded payload (RFC7797) + * Supports JWE messages with multiple recipients, both compact and JSON serialization + * Most operations work with either JWK or raw keys e.g. *rsa.PrivateKey, *ecdsa.PrivateKey, etc). +* Opinionated, but very uniform API. Everything is symmetric, and follows a standard convention + * jws.Parse/Verify/Sign + * jwe.Parse/Encrypt/Decrypt + * Arguments are organized as explicit required parameters and optional WithXXXX() style options. +* Extra utilities + * `jwk.Cache` to always keep a JWKS up-to-date + * [bazel](https://bazel.build)-ready + +Some more in-depth discussion on why you might want to use this library over others +can be found in the [Description section](#description) + +If you are using v0 or v1, you are strongly encouraged to migrate to using v3 +(the version that comes with the README you are reading). + +# SYNOPSIS + + +```go +package examples_test + +import ( + "bytes" + "fmt" + "net/http" + "time" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/jwx/v3/jwt" +) + +func Example() { + // Parse, serialize, slice and dice JWKs! + privkey, err := jwk.ParseKey(jsonRSAPrivateKey) + if err != nil { + fmt.Printf("failed to parse JWK: %s\n", err) + return + } + + pubkey, err := jwk.PublicKeyOf(privkey) + if err != nil { + fmt.Printf("failed to get public key: %s\n", err) + return + } + + // Work with JWTs! + { + // Build a JWT! + tok, err := jwt.NewBuilder(). + Issuer(`github.com/lestrrat-go/jwx`). + IssuedAt(time.Now()). + Build() + if err != nil { + fmt.Printf("failed to build token: %s\n", err) + return + } + + // Sign a JWT! + signed, err := jwt.Sign(tok, jwt.WithKey(jwa.RS256(), privkey)) + if err != nil { + fmt.Printf("failed to sign token: %s\n", err) + return + } + + // Verify a JWT! + { + verifiedToken, err := jwt.Parse(signed, jwt.WithKey(jwa.RS256(), pubkey)) + if err != nil { + fmt.Printf("failed to verify JWS: %s\n", err) + return + } + _ = verifiedToken + } + + // Work with *http.Request! + { + req, err := http.NewRequest(http.MethodGet, `https://github.com/lestrrat-go/jwx`, nil) + req.Header.Set(`Authorization`, fmt.Sprintf(`Bearer %s`, signed)) + + verifiedToken, err := jwt.ParseRequest(req, jwt.WithKey(jwa.RS256(), pubkey)) + if err != nil { + fmt.Printf("failed to verify token from HTTP request: %s\n", err) + return + } + _ = verifiedToken + } + } + + // Encrypt and Decrypt arbitrary payload with JWE! + { + encrypted, err := jwe.Encrypt(payloadLoremIpsum, jwe.WithKey(jwa.RSA_OAEP(), jwkRSAPublicKey)) + if err != nil { + fmt.Printf("failed to encrypt payload: %s\n", err) + return + } + + decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP(), jwkRSAPrivateKey)) + if err != nil { + fmt.Printf("failed to decrypt payload: %s\n", err) + return + } + + if !bytes.Equal(decrypted, payloadLoremIpsum) { + fmt.Printf("verified payload did not match\n") + return + } + } + + // Sign and Verify arbitrary payload with JWS! + { + signed, err := jws.Sign(payloadLoremIpsum, jws.WithKey(jwa.RS256(), jwkRSAPrivateKey)) + if err != nil { + fmt.Printf("failed to sign payload: %s\n", err) + return + } + + verified, err := jws.Verify(signed, jws.WithKey(jwa.RS256(), jwkRSAPublicKey)) + if err != nil { + fmt.Printf("failed to verify payload: %s\n", err) + return + } + + if !bytes.Equal(verified, payloadLoremIpsum) { + fmt.Printf("verified payload did not match\n") + return + } + } + // OUTPUT: +} +``` +source: [examples/jwx_readme_example_test.go](https://github.com/lestrrat-go/jwx/blob/v3/examples/jwx_readme_example_test.go) + + +# How-to Documentation + +* [API documentation](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3) +* [How-to style documentation](./docs) +* [Runnable Examples](./examples) + +# Description + +This Go module implements JWA, JWE, JWK, JWS, and JWT. Please see the following table for the list of +available packages: + +| Package name | Notes | +|-----------------------------------------------------------|-------------------------------------------------| +| [jwt](https://github.com/lestrrat-go/jwx/tree/v3/jwt) | [RFC 7519](https://tools.ietf.org/html/rfc7519) | +| [jwk](https://github.com/lestrrat-go/jwx/tree/v3/jwk) | [RFC 7517](https://tools.ietf.org/html/rfc7517) + [RFC 7638](https://tools.ietf.org/html/rfc7638) | +| [jwa](https://github.com/lestrrat-go/jwx/tree/v3/jwa) | [RFC 7518](https://tools.ietf.org/html/rfc7518) | +| [jws](https://github.com/lestrrat-go/jwx/tree/v3/jws) | [RFC 7515](https://tools.ietf.org/html/rfc7515) + [RFC 7797](https://tools.ietf.org/html/rfc7797) | +| [jwe](https://github.com/lestrrat-go/jwx/tree/v3/jwe) | [RFC 7516](https://tools.ietf.org/html/rfc7516) | +## History + +My goal was to write a server that heavily uses JWK and JWT. At first glance +the libraries that already exist seemed sufficient, but soon I realized that + +1. To completely implement the protocols, I needed the entire JWT, JWK, JWS, JWE (and JWA, by necessity). +2. Most of the libraries that existed only deal with a subset of the various JWx specifications that were necessary to implement their specific needs + +For example, a certain library looks like it had most of JWS, JWE, JWK covered, but then it lacked the ability to include private claims in its JWT responses. Another library had support of all the private claims, but completely lacked in its flexibility to generate various different response formats. + +Because I was writing the server side (and the client side for testing), I needed the *entire* JOSE toolset to properly implement my server, **and** they needed to be *flexible* enough to fulfill the entire spec that I was writing. + +So here's `github.com/lestrrat-go/jwx/v3`. This library is extensible, customizable, and hopefully well organized to the point that it is easy for you to slice and dice it. + +## Why would I use this library? + +There are several other major Go modules that handle JWT and related data formats, +so why should you use this library? + +From a purely functional perspective, the only major difference is this: +Whereas most other projects only deal with what they seem necessary to handle +JWTs, this module handles the **_entire_** spectrum of JWS, JWE, JWK, and JWT. + +That is, if you need to not only parse JWTs, but also to control JWKs, or +if you need to handle payloads that are NOT JWTs, you should probably consider +using this module. You should also note that JWT is built _on top_ of those +other technologies. You simply cannot have a complete JWT package without +implementing the entirety of JWS/JWE/JWK, which this library does. + +Next, from an implementation perspective, this module differs significantly +from others in that it tries very hard to expose only the APIs, and not the +internal data. For example, individual JWT claims are not accessible through +struct field lookups. You need to use one of the getter methods. + +This is because this library takes the stance that the end user is fully capable +and even willing to shoot themselves on the foot when presented with a lax +API. By making sure that users do not have access to open structs, we can protect +users from doing silly things like creating _incomplete_ structs, or access the +structs concurrently without any protection. This structure also allows +us to put extra smarts in the structs, such as doing the right thing when +you want to parse / write custom fields (this module does not require the user +to specify alternate structs to parse objects with custom fields) + +In the end I think it comes down to your usage pattern, and priorities. +Some general guidelines that come to mind are: + +* If you want a single library to handle everything JWx, such as using JWE, JWK, JWS, handling [auto-refreshing JWKs](https://github.com/lestrrat-go/jwx/blob/v3/docs/04-jwk.md#auto-refreshing-remote-keys), use this module. +* If you want to honor all possible custom fields transparently, use this module. +* If you want a standardized clean API, use this module. + +Otherwise, feel free to choose something else. + +# Contributions + +## Issues + +For bug reports and feature requests, please try to follow the issue templates as much as possible. +For either bug reports or feature requests, failing tests are even better. + +## Pull Requests + +Please make sure to include tests that exercise the changes you made. + +If you are editing auto-generated files (those files with the `_gen.go` suffix, please make sure that you do the following: + +1. Edit the generator, not the generated files (e.g. internal/cmd/genreadfile/main.go) +2. Run `make generate` (or `go generate`) to generate the new code +3. Commit _both_ the generator _and_ the generated files + +## Discussions / Usage + +Please try [discussions](https://github.com/lestrrat-go/jwx/tree/v3/discussions) first. + +# Related Modules + +* [github.com/lestrrat-go/echo-middleware-jwx](https://github.com/lestrrat-go/echo-middleware-jwx) - Sample Echo middleware +* [github.com/jwx-go/crypto-signer/gcp](https://github.com/jwx-go/crypto-signer/tree/main/gcp) - GCP KMS wrapper that implements [`crypto.Signer`](https://pkg.go.dev/crypto#Signer) +* [github.com/jwx-go/crypto-signer/aws](https://github.com/jwx-go/crypto-signer/tree/main/aws) - AWS KMS wrapper that implements [`crypto.Signer`](https://pkg.go.dev/crypto#Signer) + +# Credits + +* Initial work on this library was generously sponsored by HDE Inc (https://www.hde.co.jp) +* Lots of code, especially JWE was initially taken from go-jose library (https://github.com/square/go-jose) +* Lots of individual contributors have helped this project over the years. Thank each and everyone of you very much. + +# Quid pro quo + +If you use this software to build products in a for-profit organization, we ask you to _consider_ +contributing back to FOSS in the following manner: + +* For every 100 employees (direct hires) of your organization, please consider contributing minimum of $1 every year to either this project, **or** another FOSS projects that this project uses. For example, for 100 employees, we ask you contribute $100 yearly; for 10,000 employees, we ask you contribute $10,000 yearly. +* If possible, please make this information public. You do not need to disclose the amount you are contributing, but please make the information that you are contributing to particular FOSS projects public. For this project, please consider writing your name on the [Wiki](https://github.com/lestrrat-go/jwx/wiki/Users) + +This is _NOT_ a licensing term: you are still free to use this software according to the license it +comes with. This clause is only a plea for people to acknowledge the work from FOSS developers whose +work you rely on each and everyday. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/SECURITY.md b/vendor/github.com/lestrrat-go/jwx/v3/SECURITY.md new file mode 100644 index 0000000000..601dced5cd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +## Supported Versions + +Most recent two major versions will receive security updates + +| Version | Supported | +| -------- | ------------------ | +| v3.x.x | :white_check_mark: | +| v2.x.x | :white_check_mark: | +| < v2.0.0 | :x: | + +## Reporting a Vulnerability + +If you think you found a vulnerability, please report it via [GitHub Security Advisory](https://github.com/lestrrat-go/jwx/security/advisories/new). +Please include explicit steps to reproduce the security issue. + +We will do our best to respond in a timely manner, but please also be aware that this project is maintained by a very limited number of people. Please help us with test code and such. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/WORKSPACE b/vendor/github.com/lestrrat-go/jwx/v3/WORKSPACE new file mode 100644 index 0000000000..c8578d8b0a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/WORKSPACE @@ -0,0 +1,2 @@ +# Empty WORKSPACE file for bzlmod compatibility +# All dependencies are now managed in MODULE.bazel \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/cert/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/cert/BUILD.bazel new file mode 100644 index 0000000000..f308530bcf --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/cert/BUILD.bazel @@ -0,0 +1,34 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "cert", + srcs = [ + "cert.go", + "chain.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/cert", + visibility = ["//visibility:public"], + deps = [ + "//internal/base64", + "//internal/tokens", + ], +) + +go_test( + name = "cert_test", + srcs = [ + "cert_test.go", + "chain_test.go", + ], + deps = [ + ":cert", + "//internal/jwxtest", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":cert", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/cert/cert.go b/vendor/github.com/lestrrat-go/jwx/v3/cert/cert.go new file mode 100644 index 0000000000..efefbcb417 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/cert/cert.go @@ -0,0 +1,48 @@ +package cert + +import ( + "crypto/x509" + stdlibb64 "encoding/base64" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/base64" +) + +// Create is a wrapper around x509.CreateCertificate, but it additionally +// encodes it in base64 so that it can be easily added to `x5c` fields +func Create(rand io.Reader, template, parent *x509.Certificate, pub, priv any) ([]byte, error) { + der, err := x509.CreateCertificate(rand, template, parent, pub, priv) + if err != nil { + return nil, fmt.Errorf(`failed to create x509 certificate: %w`, err) + } + return EncodeBase64(der) +} + +// EncodeBase64 is a utility function to encode ASN.1 DER certificates +// using base64 encoding. This operation is normally done by `pem.Encode` +// but since PEM would include the markers (`-----BEGIN`, and the like) +// while `x5c` fields do not need this, this function can be used to +// shave off a few lines +func EncodeBase64(der []byte) ([]byte, error) { + enc := stdlibb64.StdEncoding + dst := make([]byte, enc.EncodedLen(len(der))) + enc.Encode(dst, der) + return dst, nil +} + +// Parse is a utility function to decode a base64 encoded +// ASN.1 DER format certificate, and to parse the byte sequence. +// The certificate must be in PKIX format, and it must not contain PEM markers +func Parse(src []byte) (*x509.Certificate, error) { + dst, err := base64.Decode(src) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode the certificate: %w`, err) + } + + cert, err := x509.ParseCertificate(dst) + if err != nil { + return nil, fmt.Errorf(`failed to parse x509 certificate: %w`, err) + } + return cert, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/cert/chain.go b/vendor/github.com/lestrrat-go/jwx/v3/cert/chain.go new file mode 100644 index 0000000000..112274669a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/cert/chain.go @@ -0,0 +1,80 @@ +package cert + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// Chain represents a certificate chain as used in the `x5c` field of +// various objects within JOSE. +// +// It stores the certificates as a list of base64 encoded []byte +// sequence. By definition these values must PKIX encoded. +type Chain struct { + certificates [][]byte +} + +func (cc Chain) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + buf.WriteByte(tokens.OpenSquareBracket) + for i, cert := range cc.certificates { + if i > 0 { + buf.WriteByte(tokens.Comma) + } + buf.WriteByte('"') + buf.Write(cert) + buf.WriteByte('"') + } + buf.WriteByte(tokens.CloseSquareBracket) + return buf.Bytes(), nil +} + +func (cc *Chain) UnmarshalJSON(data []byte) error { + var tmp []string + if err := json.Unmarshal(data, &tmp); err != nil { + return fmt.Errorf(`failed to unmarshal certificate chain: %w`, err) + } + + certs := make([][]byte, len(tmp)) + for i, cert := range tmp { + certs[i] = []byte(cert) + } + cc.certificates = certs + return nil +} + +// Get returns the n-th ASN.1 DER + base64 encoded certificate +// stored. `false` will be returned in the second argument if +// the corresponding index is out of range. +func (cc *Chain) Get(index int) ([]byte, bool) { + if index < 0 || index >= len(cc.certificates) { + return nil, false + } + + return cc.certificates[index], true +} + +// Len returns the number of certificates stored in this Chain +func (cc *Chain) Len() int { + return len(cc.certificates) +} + +var pemStart = []byte("----- BEGIN CERTIFICATE -----") +var pemEnd = []byte("----- END CERTIFICATE -----") + +func (cc *Chain) AddString(der string) error { + return cc.Add([]byte(der)) +} + +func (cc *Chain) Add(der []byte) error { + // We're going to be nice and remove marker lines if they + // give it to us + der = bytes.TrimPrefix(der, pemStart) + der = bytes.TrimSuffix(der, pemEnd) + der = bytes.TrimSpace(der) + cc.certificates = append(cc.certificates, der) + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/codecov.yml b/vendor/github.com/lestrrat-go/jwx/v3/codecov.yml new file mode 100644 index 0000000000..130effd7a6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/codecov.yml @@ -0,0 +1,2 @@ +codecov: + allow_coverage_offsets: true diff --git a/vendor/github.com/lestrrat-go/jwx/v3/format.go b/vendor/github.com/lestrrat-go/jwx/v3/format.go new file mode 100644 index 0000000000..6cb6efe7eb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/format.go @@ -0,0 +1,104 @@ +package jwx + +import ( + "bytes" + "encoding/json" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +type FormatKind int + +// These constants describe the result from guessing the format +// of the incoming buffer. +const ( + // InvalidFormat is returned when the format of the incoming buffer + // has been deemed conclusively invalid + InvalidFormat FormatKind = iota + // UnknownFormat is returned when GuessFormat was not able to conclusively + // determine the format of the + UnknownFormat + JWE + JWS + JWK + JWKS + JWT +) + +type formatHint struct { + Payload json.RawMessage `json:"payload"` // Only in JWS + Signatures json.RawMessage `json:"signatures"` // Only in JWS + Ciphertext json.RawMessage `json:"ciphertext"` // Only in JWE + KeyType json.RawMessage `json:"kty"` // Only in JWK + Keys json.RawMessage `json:"keys"` // Only in JWKS + Audience json.RawMessage `json:"aud"` // Only in JWT +} + +// GuessFormat is used to guess the format the given payload is in +// using heuristics. See the type FormatKind for a full list of +// possible types. +// +// This may be useful in determining your next action when you may +// encounter a payload that could either be a JWE, JWS, or a plain JWT. +// +// Because JWTs are almost always JWS signed, you may be thrown off +// if you pass what you think is a JWT payload to this function. +// If the function is in the "Compact" format, it means it's a JWS +// signed message, and its payload is the JWT. Therefore this function +// will return JWS, not JWT. +// +// This function requires an extra parsing of the payload, and therefore +// may be inefficient if you call it every time before parsing. +func GuessFormat(payload []byte) FormatKind { + // The check against kty, keys, and aud are something this library + // made up. for the distinctions between JWE and JWS, we used + // https://datatracker.ietf.org/doc/html/rfc7516#section-9. + // + // The above RFC described several ways to distinguish between + // a JWE and JWS JSON, but we're only using one of them + + payload = bytes.TrimSpace(payload) + if len(payload) <= 0 { + return UnknownFormat + } + + if payload[0] != tokens.OpenCurlyBracket { + // Compact format. It's probably a JWS or JWE + sep := []byte{tokens.Period} // I want to const this :/ + + // Note: this counts the number of occurrences of the + // separator, but the RFC talks about the number of segments. + // number of tokens.Period == segments - 1, so that's why we have 2 and 4 here + switch count := bytes.Count(payload, sep); count { + case 2: + return JWS + case 4: + return JWE + default: + return InvalidFormat + } + } + + // If we got here, we probably have JSON. + var h formatHint + if err := json.Unmarshal(payload, &h); err != nil { + return UnknownFormat + } + + if h.Audience != nil { + return JWT + } + if h.KeyType != nil { + return JWK + } + if h.Keys != nil { + return JWKS + } + if h.Ciphertext != nil { + return JWE + } + if h.Signatures != nil && h.Payload != nil { + return JWS + } + return UnknownFormat +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/formatkind_string_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/formatkind_string_gen.go new file mode 100644 index 0000000000..38abd1bc47 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/formatkind_string_gen.go @@ -0,0 +1,29 @@ +// Code generated by "stringer -type=FormatKind"; DO NOT EDIT. + +package jwx + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidFormat-0] + _ = x[UnknownFormat-1] + _ = x[JWE-2] + _ = x[JWS-3] + _ = x[JWK-4] + _ = x[JWKS-5] + _ = x[JWT-6] +} + +const _FormatKind_name = "InvalidFormatUnknownFormatJWEJWSJWKJWKSJWT" + +var _FormatKind_index = [...]uint8{0, 13, 26, 29, 32, 35, 39, 42} + +func (i FormatKind) String() string { + if i < 0 || i >= FormatKind(len(_FormatKind_index)-1) { + return "FormatKind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _FormatKind_name[_FormatKind_index[i]:_FormatKind_index[i+1]] +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/BUILD.bazel new file mode 100644 index 0000000000..57da5179f3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "base64", + srcs = ["base64.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/base64", + visibility = ["//:__subpackages__"], +) + +go_test( + name = "base64_test", + srcs = ["base64_test.go"], + embed = [":base64"], + deps = ["@com_github_stretchr_testify//require"], +) + +alias( + name = "go_default_library", + actual = ":base64", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/asmbase64.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/asmbase64.go new file mode 100644 index 0000000000..6e83ecc4a5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/asmbase64.go @@ -0,0 +1,51 @@ +//go:build jwx_asmbase64 + +package base64 + +import ( + "fmt" + "slices" + + asmbase64 "github.com/segmentio/asm/base64" +) + +func init() { + SetEncoder(asmEncoder{asmbase64.RawURLEncoding}) + SetDecoder(asmDecoder{}) +} + +type asmEncoder struct { + *asmbase64.Encoding +} + +func (e asmEncoder) AppendEncode(dst, src []byte) []byte { + n := e.Encoding.EncodedLen(len(src)) + dst = slices.Grow(dst, n) + e.Encoding.Encode(dst[len(dst):][:n], src) + return dst[:len(dst)+n] +} + +type asmDecoder struct{} + +func (d asmDecoder) Decode(src []byte) ([]byte, error) { + var enc *asmbase64.Encoding + switch Guess(src) { + case Std: + enc = asmbase64.StdEncoding + case RawStd: + enc = asmbase64.RawStdEncoding + case URL: + enc = asmbase64.URLEncoding + case RawURL: + enc = asmbase64.RawURLEncoding + default: + return nil, fmt.Errorf(`invalid encoding`) + } + + dst := make([]byte, enc.DecodedLen(len(src))) + n, err := enc.Decode(dst, src) + if err != nil { + return nil, fmt.Errorf(`failed to decode source: %w`, err) + } + return dst[:n], nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/base64.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/base64.go new file mode 100644 index 0000000000..5ed8e35006 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/base64/base64.go @@ -0,0 +1,139 @@ +package base64 + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "fmt" + "sync" +) + +type Decoder interface { + Decode([]byte) ([]byte, error) +} + +type Encoder interface { + Encode([]byte, []byte) + EncodedLen(int) int + EncodeToString([]byte) string + AppendEncode([]byte, []byte) []byte +} + +var muEncoder sync.RWMutex +var encoder Encoder = base64.RawURLEncoding +var muDecoder sync.RWMutex +var decoder Decoder = defaultDecoder{} + +func SetEncoder(enc Encoder) { + muEncoder.Lock() + defer muEncoder.Unlock() + encoder = enc +} + +func getEncoder() Encoder { + muEncoder.RLock() + defer muEncoder.RUnlock() + return encoder +} + +func DefaultEncoder() Encoder { + return getEncoder() +} + +func SetDecoder(dec Decoder) { + muDecoder.Lock() + defer muDecoder.Unlock() + decoder = dec +} + +func getDecoder() Decoder { + muDecoder.RLock() + defer muDecoder.RUnlock() + return decoder +} + +func Encode(src []byte) []byte { + encoder := getEncoder() + dst := make([]byte, encoder.EncodedLen(len(src))) + encoder.Encode(dst, src) + return dst +} + +func EncodeToString(src []byte) string { + return getEncoder().EncodeToString(src) +} + +func EncodeUint64ToString(v uint64) string { + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, v) + + i := 0 + for ; i < len(data); i++ { + if data[i] != 0x0 { + break + } + } + + return EncodeToString(data[i:]) +} + +const ( + InvalidEncoding = iota + Std + URL + RawStd + RawURL +) + +func Guess(src []byte) int { + var isRaw = !bytes.HasSuffix(src, []byte{'='}) + var isURL = !bytes.ContainsAny(src, "+/") + switch { + case isRaw && isURL: + return RawURL + case isURL: + return URL + case isRaw: + return RawStd + default: + return Std + } +} + +// defaultDecoder is a Decoder that detects the encoding of the source and +// decodes it accordingly. This shouldn't really be required per the spec, but +// it exist because we have seen in the wild JWTs that are encoded using +// various versions of the base64 encoding. +type defaultDecoder struct{} + +func (defaultDecoder) Decode(src []byte) ([]byte, error) { + var enc *base64.Encoding + + switch Guess(src) { + case RawURL: + enc = base64.RawURLEncoding + case URL: + enc = base64.URLEncoding + case RawStd: + enc = base64.RawStdEncoding + case Std: + enc = base64.StdEncoding + default: + return nil, fmt.Errorf(`invalid encoding`) + } + + dst := make([]byte, enc.DecodedLen(len(src))) + n, err := enc.Decode(dst, src) + if err != nil { + return nil, fmt.Errorf(`failed to decode source: %w`, err) + } + return dst[:n], nil +} + +func Decode(src []byte) ([]byte, error) { + return getDecoder().Decode(src) +} + +func DecodeString(src string) ([]byte, error) { + return getDecoder().Decode([]byte(src)) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/BUILD.bazel new file mode 100644 index 0000000000..3ccdcf372a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/BUILD.bazel @@ -0,0 +1,14 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "ecutil", + srcs = ["ecutil.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/ecutil", + visibility = ["//:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":ecutil", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/ecutil.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/ecutil.go new file mode 100644 index 0000000000..cf0bd4ac48 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/ecutil/ecutil.go @@ -0,0 +1,76 @@ +// Package ecutil defines tools that help with elliptic curve related +// computation +package ecutil + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +const ( + // size of buffer that needs to be allocated for EC521 curve + ec521BufferSize = 66 // (521 / 8) + 1 +) + +var ecpointBufferPool = sync.Pool{ + New: func() any { + // In most cases the curve bit size will be less than this length + // so allocate the maximum, and keep reusing + buf := make([]byte, 0, ec521BufferSize) + return &buf + }, +} + +func getCrvFixedBuffer(size int) []byte { + //nolint:forcetypeassert + buf := *(ecpointBufferPool.Get().(*[]byte)) + if size > ec521BufferSize && cap(buf) < size { + buf = append(buf, make([]byte, size-cap(buf))...) + } + return buf[:size] +} + +// ReleaseECPointBuffer releases the []byte buffer allocated. +func ReleaseECPointBuffer(buf []byte) { + buf = buf[:cap(buf)] + buf[0] = 0x0 + for i := 1; i < len(buf); i *= 2 { + copy(buf[i:], buf[:i]) + } + buf = buf[:0] + ecpointBufferPool.Put(&buf) +} + +func CalculateKeySize(crv elliptic.Curve) int { + // We need to create a buffer that fits the entire curve. + // If the curve size is 66, that fits in 9 bytes. If the curve + // size is 64, it fits in 8 bytes. + bits := crv.Params().BitSize + + // For most common cases we know before hand what the byte length + // is going to be. optimize + var inBytes int + switch bits { + case 224, 256, 384: // TODO: use constant? + inBytes = bits / 8 + case 521: + inBytes = ec521BufferSize + default: + inBytes = bits / 8 + if (bits % 8) != 0 { + inBytes++ + } + } + + return inBytes +} + +// AllocECPointBuffer allocates a buffer for the given point in the given +// curve. This buffer should be released using the ReleaseECPointBuffer +// function. +func AllocECPointBuffer(v *big.Int, crv elliptic.Curve) []byte { + buf := getCrvFixedBuffer(CalculateKeySize(crv)) + v.FillBytes(buf) + return buf +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/BUILD.bazel new file mode 100644 index 0000000000..4e2dbe12b7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "json", + srcs = [ + "json.go", + "registry.go", + "stdlib.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/internal/json", + visibility = ["//:__subpackages__"], + deps = ["//internal/base64"], +) + +alias( + name = "go_default_library", + actual = ":json", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/goccy.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/goccy.go new file mode 100644 index 0000000000..e70a3c1edc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/goccy.go @@ -0,0 +1,49 @@ +//go:build jwx_goccy +// +build jwx_goccy + +package json + +import ( + "io" + + "github.com/goccy/go-json" +) + +type Decoder = json.Decoder +type Delim = json.Delim +type Encoder = json.Encoder +type Marshaler = json.Marshaler +type Number = json.Number +type RawMessage = json.RawMessage +type Unmarshaler = json.Unmarshaler + +func Engine() string { + return "github.com/goccy/go-json" +} + +// NewDecoder respects the values specified in DecoderSettings, +// and creates a Decoder that has certain features turned on/off +func NewDecoder(r io.Reader) *json.Decoder { + dec := json.NewDecoder(r) + + if UseNumber() { + dec.UseNumber() + } + + return dec +} + +// NewEncoder is just a proxy for "encoding/json".NewEncoder +func NewEncoder(w io.Writer) *json.Encoder { + return json.NewEncoder(w) +} + +// Marshal is just a proxy for "encoding/json".Marshal +func Marshal(v any) ([]byte, error) { + return json.Marshal(v) +} + +// MarshalIndent is just a proxy for "encoding/json".MarshalIndent +func MarshalIndent(v any, prefix, indent string) ([]byte, error) { + return json.MarshalIndent(v, prefix, indent) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/json.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/json.go new file mode 100644 index 0000000000..c1917ef27a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/json.go @@ -0,0 +1,127 @@ +package json + +import ( + "bytes" + "fmt" + "os" + "sync/atomic" + + "github.com/lestrrat-go/jwx/v3/internal/base64" +) + +var useNumber uint32 // TODO: at some point, change to atomic.Bool + +func UseNumber() bool { + return atomic.LoadUint32(&useNumber) == 1 +} + +// Sets the global configuration for json decoding +func DecoderSettings(inUseNumber bool) { + var val uint32 + if inUseNumber { + val = 1 + } + atomic.StoreUint32(&useNumber, val) +} + +// Unmarshal respects the values specified in DecoderSettings, +// and uses a Decoder that has certain features turned on/off +func Unmarshal(b []byte, v any) error { + dec := NewDecoder(bytes.NewReader(b)) + return dec.Decode(v) +} + +func AssignNextBytesToken(dst *[]byte, dec *Decoder) error { + var val string + if err := dec.Decode(&val); err != nil { + return fmt.Errorf(`error reading next value: %w`, err) + } + + buf, err := base64.DecodeString(val) + if err != nil { + return fmt.Errorf(`expected base64 encoded []byte (%T)`, val) + } + *dst = buf + return nil +} + +func ReadNextStringToken(dec *Decoder) (string, error) { + var val string + if err := dec.Decode(&val); err != nil { + return "", fmt.Errorf(`error reading next value: %w`, err) + } + return val, nil +} + +func AssignNextStringToken(dst **string, dec *Decoder) error { + val, err := ReadNextStringToken(dec) + if err != nil { + return err + } + *dst = &val + return nil +} + +// FlattenAudience is a flag to specify if we should flatten the "aud" +// entry to a string when there's only one entry. +// In jwx < 1.1.8 we just dumped everything as an array of strings, +// but apparently AWS Cognito doesn't handle this well. +// +// So now we have the ability to dump "aud" as a string if there's +// only one entry, but we need to retain the old behavior so that +// we don't accidentally break somebody else's code. (e.g. messing +// up how signatures are calculated) +var FlattenAudience uint32 + +func MarshalAudience(aud []string, flatten bool) ([]byte, error) { + var val any + if len(aud) == 1 && flatten { + val = aud[0] + } else { + val = aud + } + return Marshal(val) +} + +func EncodeAudience(enc *Encoder, aud []string, flatten bool) error { + var val any + if len(aud) == 1 && flatten { + val = aud[0] + } else { + val = aud + } + return enc.Encode(val) +} + +// DecodeCtx is an interface for objects that needs that extra something +// when decoding JSON into an object. +type DecodeCtx interface { + Registry() *Registry +} + +// DecodeCtxContainer is used to differentiate objects that can carry extra +// decoding hints and those who can't. +type DecodeCtxContainer interface { + DecodeCtx() DecodeCtx + SetDecodeCtx(DecodeCtx) +} + +// stock decodeCtx. should cover 80% of the cases +type decodeCtx struct { + registry *Registry +} + +func NewDecodeCtx(r *Registry) DecodeCtx { + return &decodeCtx{registry: r} +} + +func (dc *decodeCtx) Registry() *Registry { + return dc.registry +} + +func Dump(v any) { + enc := NewEncoder(os.Stdout) + enc.SetIndent("", " ") + //nolint:errchkjson + _ = enc.Encode(v) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/registry.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/registry.go new file mode 100644 index 0000000000..04a6a4c4a5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/registry.go @@ -0,0 +1,90 @@ +package json + +import ( + "fmt" + "reflect" + "sync" +) + +// CustomDecoder is the interface we expect from RegisterCustomField in jws, jwe, jwk, and jwt packages. +type CustomDecoder interface { + // Decode takes a JSON encoded byte slice and returns the desired + // decoded value,which will be used as the value for that field + // registered through RegisterCustomField + Decode([]byte) (any, error) +} + +// CustomDecodeFunc is a stateless, function-based implementation of CustomDecoder +type CustomDecodeFunc func([]byte) (any, error) + +func (fn CustomDecodeFunc) Decode(data []byte) (any, error) { + return fn(data) +} + +type objectTypeDecoder struct { + typ reflect.Type + name string +} + +func (dec *objectTypeDecoder) Decode(data []byte) (any, error) { + ptr := reflect.New(dec.typ).Interface() + if err := Unmarshal(data, ptr); err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, dec.name, err) + } + return reflect.ValueOf(ptr).Elem().Interface(), nil +} + +type Registry struct { + mu *sync.RWMutex + ctrs map[string]CustomDecoder +} + +func NewRegistry() *Registry { + return &Registry{ + mu: &sync.RWMutex{}, + ctrs: make(map[string]CustomDecoder), + } +} + +func (r *Registry) Register(name string, object any) { + if object == nil { + r.mu.Lock() + defer r.mu.Unlock() + delete(r.ctrs, name) + return + } + + r.mu.Lock() + defer r.mu.Unlock() + if ctr, ok := object.(CustomDecoder); ok { + r.ctrs[name] = ctr + } else { + r.ctrs[name] = &objectTypeDecoder{ + typ: reflect.TypeOf(object), + name: name, + } + } +} + +func (r *Registry) Decode(dec *Decoder, name string) (any, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if ctr, ok := r.ctrs[name]; ok { + var raw RawMessage + if err := dec.Decode(&raw); err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, name, err) + } + v, err := ctr.Decode([]byte(raw)) + if err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, name, err) + } + return v, nil + } + + var decoded any + if err := dec.Decode(&decoded); err != nil { + return nil, fmt.Errorf(`failed to decode field %s: %w`, name, err) + } + return decoded, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/json/stdlib.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/stdlib.go new file mode 100644 index 0000000000..6f416ec89a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/json/stdlib.go @@ -0,0 +1,47 @@ +//go:build !jwx_goccy +// +build !jwx_goccy + +package json + +import ( + "encoding/json" + "io" +) + +type Decoder = json.Decoder +type Delim = json.Delim +type Encoder = json.Encoder +type Marshaler = json.Marshaler +type Number = json.Number +type RawMessage = json.RawMessage +type Unmarshaler = json.Unmarshaler + +func Engine() string { + return "encoding/json" +} + +// NewDecoder respects the values specified in DecoderSettings, +// and creates a Decoder that has certain features turned on/off +func NewDecoder(r io.Reader) *json.Decoder { + dec := json.NewDecoder(r) + + if UseNumber() { + dec.UseNumber() + } + + return dec +} + +func NewEncoder(w io.Writer) *json.Encoder { + return json.NewEncoder(w) +} + +// Marshal is just a proxy for "encoding/json".Marshal +func Marshal(v any) ([]byte, error) { + return json.Marshal(v) +} + +// MarshalIndent is just a proxy for "encoding/json".MarshalIndent +func MarshalIndent(v any, prefix, indent string) ([]byte, error) { + return json.MarshalIndent(v, prefix, indent) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/BUILD.bazel new file mode 100644 index 0000000000..c70c4d2871 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/BUILD.bazel @@ -0,0 +1,8 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "jwxio", + srcs = ["jwxio.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/jwxio", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/jwxio.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/jwxio.go new file mode 100644 index 0000000000..8396417a9d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/jwxio/jwxio.go @@ -0,0 +1,29 @@ +package jwxio + +import ( + "bytes" + "errors" + "io" + "strings" +) + +var errNonFiniteSource = errors.New(`cannot read from non-finite source`) + +func NonFiniteSourceError() error { + return errNonFiniteSource +} + +// ReadAllFromFiniteSource reads all data from a io.Reader _if_ it comes from a +// finite source. +func ReadAllFromFiniteSource(rdr io.Reader) ([]byte, error) { + switch rdr.(type) { + case *bytes.Reader, *bytes.Buffer, *strings.Reader: + data, err := io.ReadAll(rdr) + if err != nil { + return nil, err + } + return data, nil + default: + return nil, errNonFiniteSource + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/BUILD.bazel new file mode 100644 index 0000000000..d46d2f3814 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/BUILD.bazel @@ -0,0 +1,31 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "keyconv", + srcs = ["keyconv.go"], + importpath = "github.com/lestrrat-go/jwx/v3/internal/keyconv", + visibility = ["//:__subpackages__"], + deps = [ + "//jwk", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@org_golang_x_crypto//ed25519", + ], +) + +go_test( + name = "keyconv_test", + srcs = ["keyconv_test.go"], + deps = [ + ":keyconv", + "//internal/jwxtest", + "//jwa", + "//jwk", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":keyconv", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/keyconv.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/keyconv.go new file mode 100644 index 0000000000..b911839c5d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/keyconv/keyconv.go @@ -0,0 +1,265 @@ +package keyconv + +import ( + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// RSAPrivateKey assigns src to dst. +// `dst` should be a pointer to a rsa.PrivateKey. +// `src` may be rsa.PrivateKey, *rsa.PrivateKey, or a jwk.Key +func RSAPrivateKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw rsa.PrivateKey + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`failed to produce rsa.PrivateKey from %T: %w`, src, err) + } + src = &raw + } + + var ptr *rsa.PrivateKey + switch src := src.(type) { + case rsa.PrivateKey: + ptr = &src + case *rsa.PrivateKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected rsa.PrivateKey or *rsa.PrivateKey, got %T`, src) + } + + return blackmagic.AssignIfCompatible(dst, ptr) +} + +// RSAPublicKey assigns src to dst +// `dst` should be a pointer to a non-zero rsa.PublicKey. +// `src` may be rsa.PublicKey, *rsa.PublicKey, or a jwk.Key +func RSAPublicKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + pk, err := jwk.PublicRawKeyOf(jwkKey) + if err != nil { + return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err) + } + src = pk + } + + var ptr *rsa.PublicKey + switch src := src.(type) { + case rsa.PrivateKey: + ptr = &src.PublicKey + case *rsa.PrivateKey: + ptr = &src.PublicKey + case rsa.PublicKey: + ptr = &src + case *rsa.PublicKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected rsa.PublicKey/rsa.PrivateKey or *rsa.PublicKey/*rsa.PrivateKey, got %T`, src) + } + + return blackmagic.AssignIfCompatible(dst, ptr) +} + +// ECDSAPrivateKey assigns src to dst, converting its type from a +// non-pointer to a pointer +func ECDSAPrivateKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw ecdsa.PrivateKey + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`keyconv: failed to produce ecdsa.PrivateKey from %T: %w`, src, err) + } + src = &raw + } + + var ptr *ecdsa.PrivateKey + switch src := src.(type) { + case ecdsa.PrivateKey: + ptr = &src + case *ecdsa.PrivateKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected ecdsa.PrivateKey or *ecdsa.PrivateKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +// ECDSAPublicKey assigns src to dst, converting its type from a +// non-pointer to a pointer +func ECDSAPublicKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + pk, err := jwk.PublicRawKeyOf(jwkKey) + if err != nil { + return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err) + } + src = pk + } + + var ptr *ecdsa.PublicKey + switch src := src.(type) { + case ecdsa.PrivateKey: + ptr = &src.PublicKey + case *ecdsa.PrivateKey: + ptr = &src.PublicKey + case ecdsa.PublicKey: + ptr = &src + case *ecdsa.PublicKey: + ptr = src + default: + return fmt.Errorf(`keyconv: expected ecdsa.PublicKey/ecdsa.PrivateKey or *ecdsa.PublicKey/*ecdsa.PrivateKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +func ByteSliceKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw []byte + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`keyconv: failed to produce []byte from %T: %w`, src, err) + } + src = raw + } + + if _, ok := src.([]byte); !ok { + return fmt.Errorf(`keyconv: expected []byte, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, src) +} + +func Ed25519PrivateKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + var raw ed25519.PrivateKey + if err := jwk.Export(jwkKey, &raw); err != nil { + return fmt.Errorf(`failed to produce ed25519.PrivateKey from %T: %w`, src, err) + } + src = &raw + } + + var ptr *ed25519.PrivateKey + switch src := src.(type) { + case ed25519.PrivateKey: + ptr = &src + case *ed25519.PrivateKey: + ptr = src + default: + return fmt.Errorf(`expected ed25519.PrivateKey or *ed25519.PrivateKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +func Ed25519PublicKey(dst, src any) error { + if jwkKey, ok := src.(jwk.Key); ok { + pk, err := jwk.PublicRawKeyOf(jwkKey) + if err != nil { + return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err) + } + src = pk + } + + switch key := src.(type) { + case ed25519.PrivateKey: + src = key.Public() + case *ed25519.PrivateKey: + src = key.Public() + } + + var ptr *ed25519.PublicKey + switch src := src.(type) { + case ed25519.PublicKey: + ptr = &src + case *ed25519.PublicKey: + ptr = src + case *crypto.PublicKey: + tmp, ok := (*src).(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`failed to retrieve ed25519.PublicKey out of *crypto.PublicKey`) + } + ptr = &tmp + case crypto.PublicKey: + tmp, ok := src.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`failed to retrieve ed25519.PublicKey out of crypto.PublicKey`) + } + ptr = &tmp + default: + return fmt.Errorf(`expected ed25519.PublicKey or *ed25519.PublicKey, got %T`, src) + } + return blackmagic.AssignIfCompatible(dst, ptr) +} + +type privECDHer interface { + ECDH() (*ecdh.PrivateKey, error) +} + +func ECDHPrivateKey(dst, src any) error { + var privECDH *ecdh.PrivateKey + if jwkKey, ok := src.(jwk.Key); ok { + var rawECDH ecdh.PrivateKey + if err := jwk.Export(jwkKey, &rawECDH); err == nil { + privECDH = &rawECDH + } else { + // If we cannot export the key as an ecdh.PrivateKey, we try to export it as an ecdsa.PrivateKey + var rawECDSA ecdsa.PrivateKey + if err := jwk.Export(jwkKey, &rawECDSA); err != nil { + return fmt.Errorf(`keyconv: failed to produce ecdh.PrivateKey or ecdsa.PrivateKey from %T: %w`, src, err) + } + src = &rawECDSA + } + } + + switch src := src.(type) { + case ecdh.PrivateKey: + privECDH = &src + case *ecdh.PrivateKey: + privECDH = src + case privECDHer: + priv, err := src.ECDH() + if err != nil { + return fmt.Errorf(`keyconv: failed to convert ecdsa.PrivateKey to ecdh.PrivateKey: %w`, err) + } + privECDH = priv + } + + return blackmagic.AssignIfCompatible(dst, privECDH) +} + +type pubECDHer interface { + ECDH() (*ecdh.PublicKey, error) +} + +func ECDHPublicKey(dst, src any) error { + var pubECDH *ecdh.PublicKey + if jwkKey, ok := src.(jwk.Key); ok { + var rawECDH ecdh.PublicKey + if err := jwk.Export(jwkKey, &rawECDH); err == nil { + pubECDH = &rawECDH + } else { + // If we cannot export the key as an ecdh.PublicKey, we try to export it as an ecdsa.PublicKey + var rawECDSA ecdsa.PublicKey + if err := jwk.Export(jwkKey, &rawECDSA); err != nil { + return fmt.Errorf(`keyconv: failed to produce ecdh.PublicKey or ecdsa.PublicKey from %T: %w`, src, err) + } + src = &rawECDSA + } + } + + switch src := src.(type) { + case ecdh.PublicKey: + pubECDH = &src + case *ecdh.PublicKey: + pubECDH = src + case pubECDHer: + pub, err := src.ECDH() + if err != nil { + return fmt.Errorf(`keyconv: failed to convert ecdsa.PublicKey to ecdh.PublicKey: %w`, err) + } + pubECDH = pub + } + + return blackmagic.AssignIfCompatible(dst, pubECDH) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/BUILD.bazel new file mode 100644 index 0000000000..cebc269330 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "pool", + srcs = [ + "big_int.go", + "byte_slice.go", + "bytes_buffer.go", + "error_slice.go", + "key_to_error_map.go", + "pool.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/internal/pool", + visibility = ["//:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":pool", + visibility = ["//:__subpackages__"], +) + +go_test( + name = "pool_test", + srcs = [ + "byte_slice_test.go", + ], + deps = [ + ":pool", + "@com_github_stretchr_testify//require", + ], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/big_int.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/big_int.go new file mode 100644 index 0000000000..57c446d4d2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/big_int.go @@ -0,0 +1,19 @@ +package pool + +import "math/big" + +var bigIntPool = New[*big.Int](allocBigInt, freeBigInt) + +func allocBigInt() *big.Int { + return &big.Int{} +} + +func freeBigInt(b *big.Int) *big.Int { + b.SetInt64(0) // Reset the value to zero + return b +} + +// BigInt returns a pool of *big.Int instances. +func BigInt() *Pool[*big.Int] { + return bigIntPool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/byte_slice.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/byte_slice.go new file mode 100644 index 0000000000..46f1028343 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/byte_slice.go @@ -0,0 +1,19 @@ +package pool + +var byteSlicePool = SlicePool[byte]{ + pool: New[[]byte](allocByteSlice, freeByteSlice), +} + +func allocByteSlice() []byte { + return make([]byte, 0, 64) // Default capacity of 64 bytes +} + +func freeByteSlice(b []byte) []byte { + clear(b) + b = b[:0] // Reset the slice to zero length + return b +} + +func ByteSlice() SlicePool[byte] { + return byteSlicePool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/bytes_buffer.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/bytes_buffer.go new file mode 100644 index 0000000000..a877f73ff8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/bytes_buffer.go @@ -0,0 +1,18 @@ +package pool + +import "bytes" + +var bytesBufferPool = New[*bytes.Buffer](allocBytesBuffer, freeBytesBuffer) + +func allocBytesBuffer() *bytes.Buffer { + return &bytes.Buffer{} +} + +func freeBytesBuffer(b *bytes.Buffer) *bytes.Buffer { + b.Reset() + return b +} + +func BytesBuffer() *Pool[*bytes.Buffer] { + return bytesBufferPool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/error_slice.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/error_slice.go new file mode 100644 index 0000000000..4f1675c1c0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/error_slice.go @@ -0,0 +1,16 @@ +package pool + +var errorSlicePool = New[[]error](allocErrorSlice, freeErrorSlice) + +func allocErrorSlice() []error { + return make([]error, 0, 1) +} + +func freeErrorSlice(s []error) []error { + // Reset the slice to its zero value + return s[:0] +} + +func ErrorSlice() *Pool[[]error] { + return errorSlicePool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/key_to_error_map.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/key_to_error_map.go new file mode 100644 index 0000000000..9fae012644 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/key_to_error_map.go @@ -0,0 +1,19 @@ +package pool + +var keyToErrorMapPool = New[map[string]error](allocKeyToErrorMap, freeKeyToErrorMap) + +func allocKeyToErrorMap() map[string]error { + return make(map[string]error) +} + +func freeKeyToErrorMap(m map[string]error) map[string]error { + for k := range m { + delete(m, k) // Clear the map + } + return m +} + +// KeyToErrorMap returns a pool of map[string]error instances. +func KeyToErrorMap() *Pool[map[string]error] { + return keyToErrorMapPool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/pool.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/pool.go new file mode 100644 index 0000000000..008b1cdb8b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/pool/pool.go @@ -0,0 +1,70 @@ +package pool + +import ( + "sync" +) + +type Pool[T any] struct { + pool sync.Pool + destructor func(T) T +} + +// New creates a new Pool instance for the type T. +// The allocator function is used to create new instances of T when the pool is empty. +// The destructor function is used to clean up instances of T before they are returned to the pool. +// The destructor should reset the state of T to a clean state, so it can be reused, and +// return the modified instance of T. This is required for cases when you reset operations +// can modify the underlying data structure, such as slices or maps. +func New[T any](allocator func() T, destructor func(T) T) *Pool[T] { + return &Pool[T]{ + pool: sync.Pool{ + New: func() any { + return allocator() + }, + }, + destructor: destructor, + } +} + +// Get retrieves an item of type T from the pool. +func (p *Pool[T]) Get() T { + //nolint:forcetypeassert + return p.pool.Get().(T) +} + +// Put returns an item of type T to the pool. +// The item is first processed by the destructor function to ensure it is in a clean state. +func (p *Pool[T]) Put(item T) { + p.pool.Put(p.destructor(item)) +} + +// SlicePool is a specialized pool for slices of type T. It is identical to Pool[T] but +// provides additional functionality to get slices with a specific capacity. +type SlicePool[T any] struct { + pool *Pool[[]T] +} + +func NewSlicePool[T any](allocator func() []T, destructor func([]T) []T) SlicePool[T] { + return SlicePool[T]{ + pool: New(allocator, destructor), + } +} + +func (p SlicePool[T]) Get() []T { + return p.pool.Get() +} + +func (p SlicePool[T]) GetCapacity(capacity int) []T { + if capacity <= 0 { + return p.Get() + } + s := p.Get() + if cap(s) < capacity { + s = make([]T, 0, capacity) + } + return s +} + +func (p SlicePool[T]) Put(s []T) { + p.pool.Put(s) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/BUILD.bazel new file mode 100644 index 0000000000..6a331efb34 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/BUILD.bazel @@ -0,0 +1,17 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "tokens", + srcs = [ + "jwe_tokens.go", + "tokens.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/internal/tokens", + visibility = ["//:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":tokens", + visibility = ["//:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/jwe_tokens.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/jwe_tokens.go new file mode 100644 index 0000000000..9001cbbbc7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/jwe_tokens.go @@ -0,0 +1,48 @@ +package tokens + +// JWE Key Encryption Algorithms +const ( + // RSA algorithms + RSA1_5 = "RSA1_5" + RSA_OAEP = "RSA-OAEP" + RSA_OAEP_256 = "RSA-OAEP-256" + RSA_OAEP_384 = "RSA-OAEP-384" + RSA_OAEP_512 = "RSA-OAEP-512" + + // AES Key Wrap algorithms + A128KW = "A128KW" + A192KW = "A192KW" + A256KW = "A256KW" + + // AES GCM Key Wrap algorithms + A128GCMKW = "A128GCMKW" + A192GCMKW = "A192GCMKW" + A256GCMKW = "A256GCMKW" + + // ECDH-ES algorithms + ECDH_ES = "ECDH-ES" + ECDH_ES_A128KW = "ECDH-ES+A128KW" + ECDH_ES_A192KW = "ECDH-ES+A192KW" + ECDH_ES_A256KW = "ECDH-ES+A256KW" + + // PBES2 algorithms + PBES2_HS256_A128KW = "PBES2-HS256+A128KW" + PBES2_HS384_A192KW = "PBES2-HS384+A192KW" + PBES2_HS512_A256KW = "PBES2-HS512+A256KW" + + // Direct key agreement + DIRECT = "dir" +) + +// JWE Content Encryption Algorithms +const ( + // AES GCM algorithms + A128GCM = "A128GCM" + A192GCM = "A192GCM" + A256GCM = "A256GCM" + + // AES CBC + HMAC algorithms + A128CBC_HS256 = "A128CBC-HS256" + A192CBC_HS384 = "A192CBC-HS384" + A256CBC_HS512 = "A256CBC-HS512" +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/tokens.go b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/tokens.go new file mode 100644 index 0000000000..2af3b88de1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/internal/tokens/tokens.go @@ -0,0 +1,51 @@ +package tokens + +const ( + CloseCurlyBracket = '}' + CloseSquareBracket = ']' + Colon = ':' + Comma = ',' + DoubleQuote = '"' + OpenCurlyBracket = '{' + OpenSquareBracket = '[' + Period = '.' +) + +// Cryptographic key sizes +const ( + KeySize16 = 16 + KeySize24 = 24 + KeySize32 = 32 + KeySize48 = 48 // A192CBC_HS384 key size + KeySize64 = 64 // A256CBC_HS512 key size +) + +// Bit/byte conversion factors +const ( + BitsPerByte = 8 + BytesPerBit = 1.0 / 8 +) + +// Key wrapping constants +const ( + KeywrapChunkLen = 8 + KeywrapRounds = 6 // RFC 3394 key wrap rounds + KeywrapBlockSize = 8 // Key wrap block size in bytes +) + +// AES-GCM constants +const ( + GCMIVSize = 12 // GCM IV size in bytes (96 bits) + GCMTagSize = 16 // GCM tag size in bytes (128 bits) +) + +// PBES2 constants +const ( + PBES2DefaultIterations = 10000 // Default PBKDF2 iteration count + PBES2NullByteSeparator = 0 // Null byte separator for PBES2 +) + +// RSA key generation constants +const ( + RSAKeyGenMultiplier = 2 // RSA key generation size multiplier +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwa/BUILD.bazel new file mode 100644 index 0000000000..cfb7af02a0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/BUILD.bazel @@ -0,0 +1,45 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwa", + srcs = [ + "compression_gen.go", + "content_encryption_gen.go", + "elliptic_gen.go", + "jwa.go", + "key_encryption_gen.go", + "key_type_gen.go", + "options_gen.go", + "signature_gen.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwa", + visibility = ["//visibility:public"], + deps = [ + "//internal/tokens", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwa_test", + srcs = [ + "compression_gen_test.go", + "content_encryption_gen_test.go", + "elliptic_gen_test.go", + "jwa_test.go", + "key_encryption_gen_test.go", + "key_type_gen_test.go", + "signature_gen_test.go", + ], + deps = [ + ":jwa", + "@com_github_stretchr_testify//require", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +alias( + name = "go_default_library", + actual = ":jwa", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwa/README.md new file mode 100644 index 0000000000..270e60c672 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/README.md @@ -0,0 +1,3 @@ +# JWA [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwa.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwa) + +Package [github.com/lestrrat-go/jwx/v3/jwa](./jwa) defines the various algorithm described in [RFC7518](https://tools.ietf.org/html/rfc7518) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/compression_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/compression_gen.go new file mode 100644 index 0000000000..a7a2451afa --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/compression_gen.go @@ -0,0 +1,153 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllCompressionAlgorithm sync.RWMutex +var allCompressionAlgorithm = map[string]CompressionAlgorithm{} +var muListCompressionAlgorithm sync.RWMutex +var listCompressionAlgorithm []CompressionAlgorithm +var builtinCompressionAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for CompressionAlgorithm + algorithms := make([]CompressionAlgorithm, 2) + algorithms[0] = NewCompressionAlgorithm("DEF") + algorithms[1] = NewCompressionAlgorithm("") + + RegisterCompressionAlgorithm(algorithms...) +} + +// Deflate returns an object representing the "DEF" content compression algorithm value. Using this value specifies that the content should be compressed using DEFLATE (RFC 1951). +func Deflate() CompressionAlgorithm { + return lookupBuiltinCompressionAlgorithm("DEF") +} + +// NoCompress returns an object representing an empty compression algorithm value. Using this value specifies that the content should not be compressed. +func NoCompress() CompressionAlgorithm { + return lookupBuiltinCompressionAlgorithm("") +} + +func lookupBuiltinCompressionAlgorithm(name string) CompressionAlgorithm { + muAllCompressionAlgorithm.RLock() + v, ok := allCompressionAlgorithm[name] + muAllCompressionAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: CompressionAlgorithm %q not registered`, name)) + } + return v +} + +// CompressionAlgorithm represents the compression algorithms as described in https://tools.ietf.org/html/rfc7518#section-7.3 +type CompressionAlgorithm struct { + name string + deprecated bool +} + +func (s CompressionAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the CompressionAlgorithm object is deprecated. +func (s CompressionAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// EmptyCompressionAlgorithm returns an empty CompressionAlgorithm object, used as a zero value. +func EmptyCompressionAlgorithm() CompressionAlgorithm { + return CompressionAlgorithm{} +} + +// NewCompressionAlgorithm creates a new CompressionAlgorithm object with the given name. +func NewCompressionAlgorithm(name string, options ...NewAlgorithmOption) CompressionAlgorithm { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewCompressionAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return CompressionAlgorithm{name: name, deprecated: deprecated} +} + +// LookupCompressionAlgorithm returns the CompressionAlgorithm object for the given name. +func LookupCompressionAlgorithm(name string) (CompressionAlgorithm, bool) { + muAllCompressionAlgorithm.RLock() + v, ok := allCompressionAlgorithm[name] + muAllCompressionAlgorithm.RUnlock() + return v, ok +} + +// RegisterCompressionAlgorithm registers a new CompressionAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterCompressionAlgorithm(algorithms ...CompressionAlgorithm) { + muAllCompressionAlgorithm.Lock() + for _, alg := range algorithms { + allCompressionAlgorithm[alg.String()] = alg + } + muAllCompressionAlgorithm.Unlock() + rebuildCompressionAlgorithm() +} + +// UnregisterCompressionAlgorithm unregisters a CompressionAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterCompressionAlgorithm(algorithms ...CompressionAlgorithm) { + muAllCompressionAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinCompressionAlgorithm[alg.String()]; ok { + continue + } + delete(allCompressionAlgorithm, alg.String()) + } + muAllCompressionAlgorithm.Unlock() + rebuildCompressionAlgorithm() +} + +func rebuildCompressionAlgorithm() { + list := make([]CompressionAlgorithm, 0, len(allCompressionAlgorithm)) + muAllCompressionAlgorithm.RLock() + for _, v := range allCompressionAlgorithm { + list = append(list, v) + } + muAllCompressionAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListCompressionAlgorithm.Lock() + listCompressionAlgorithm = list + muListCompressionAlgorithm.Unlock() +} + +// CompressionAlgorithms returns a list of all available values for CompressionAlgorithm. +func CompressionAlgorithms() []CompressionAlgorithm { + muListCompressionAlgorithm.RLock() + defer muListCompressionAlgorithm.RUnlock() + return listCompressionAlgorithm +} + +// MarshalJSON serializes the CompressionAlgorithm object to a JSON string. +func (s CompressionAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a CompressionAlgorithm object. +func (s *CompressionAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal CompressionAlgorithm: %w`, err) + } + v, ok := LookupCompressionAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown CompressionAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/content_encryption_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/content_encryption_gen.go new file mode 100644 index 0000000000..8ccc47e462 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/content_encryption_gen.go @@ -0,0 +1,179 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +var muAllContentEncryptionAlgorithm sync.RWMutex +var allContentEncryptionAlgorithm = map[string]ContentEncryptionAlgorithm{} +var muListContentEncryptionAlgorithm sync.RWMutex +var listContentEncryptionAlgorithm []ContentEncryptionAlgorithm +var builtinContentEncryptionAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for ContentEncryptionAlgorithm + algorithms := make([]ContentEncryptionAlgorithm, 6) + algorithms[0] = NewContentEncryptionAlgorithm(tokens.A128CBC_HS256) + algorithms[1] = NewContentEncryptionAlgorithm(tokens.A128GCM) + algorithms[2] = NewContentEncryptionAlgorithm(tokens.A192CBC_HS384) + algorithms[3] = NewContentEncryptionAlgorithm(tokens.A192GCM) + algorithms[4] = NewContentEncryptionAlgorithm(tokens.A256CBC_HS512) + algorithms[5] = NewContentEncryptionAlgorithm(tokens.A256GCM) + + RegisterContentEncryptionAlgorithm(algorithms...) +} + +// A128CBC_HS256 returns an object representing A128CBC-HS256. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA256 (128). +func A128CBC_HS256() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A128CBC_HS256) +} + +// A128GCM returns an object representing A128GCM. Using this value specifies that the content should be encrypted using AES-GCM (128). +func A128GCM() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A128GCM) +} + +// A192CBC_HS384 returns an object representing A192CBC-HS384. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA384 (192). +func A192CBC_HS384() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A192CBC_HS384) +} + +// A192GCM returns an object representing A192GCM. Using this value specifies that the content should be encrypted using AES-GCM (192). +func A192GCM() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A192GCM) +} + +// A256CBC_HS512 returns an object representing A256CBC-HS512. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA512 (256). +func A256CBC_HS512() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A256CBC_HS512) +} + +// A256GCM returns an object representing A256GCM. Using this value specifies that the content should be encrypted using AES-GCM (256). +func A256GCM() ContentEncryptionAlgorithm { + return lookupBuiltinContentEncryptionAlgorithm(tokens.A256GCM) +} + +func lookupBuiltinContentEncryptionAlgorithm(name string) ContentEncryptionAlgorithm { + muAllContentEncryptionAlgorithm.RLock() + v, ok := allContentEncryptionAlgorithm[name] + muAllContentEncryptionAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: ContentEncryptionAlgorithm %q not registered`, name)) + } + return v +} + +// ContentEncryptionAlgorithm represents the various encryption algorithms as described in https://tools.ietf.org/html/rfc7518#section-5 +type ContentEncryptionAlgorithm struct { + name string + deprecated bool +} + +func (s ContentEncryptionAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the ContentEncryptionAlgorithm object is deprecated. +func (s ContentEncryptionAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// EmptyContentEncryptionAlgorithm returns an empty ContentEncryptionAlgorithm object, used as a zero value. +func EmptyContentEncryptionAlgorithm() ContentEncryptionAlgorithm { + return ContentEncryptionAlgorithm{} +} + +// NewContentEncryptionAlgorithm creates a new ContentEncryptionAlgorithm object with the given name. +func NewContentEncryptionAlgorithm(name string, options ...NewAlgorithmOption) ContentEncryptionAlgorithm { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewContentEncryptionAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return ContentEncryptionAlgorithm{name: name, deprecated: deprecated} +} + +// LookupContentEncryptionAlgorithm returns the ContentEncryptionAlgorithm object for the given name. +func LookupContentEncryptionAlgorithm(name string) (ContentEncryptionAlgorithm, bool) { + muAllContentEncryptionAlgorithm.RLock() + v, ok := allContentEncryptionAlgorithm[name] + muAllContentEncryptionAlgorithm.RUnlock() + return v, ok +} + +// RegisterContentEncryptionAlgorithm registers a new ContentEncryptionAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterContentEncryptionAlgorithm(algorithms ...ContentEncryptionAlgorithm) { + muAllContentEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + allContentEncryptionAlgorithm[alg.String()] = alg + } + muAllContentEncryptionAlgorithm.Unlock() + rebuildContentEncryptionAlgorithm() +} + +// UnregisterContentEncryptionAlgorithm unregisters a ContentEncryptionAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterContentEncryptionAlgorithm(algorithms ...ContentEncryptionAlgorithm) { + muAllContentEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinContentEncryptionAlgorithm[alg.String()]; ok { + continue + } + delete(allContentEncryptionAlgorithm, alg.String()) + } + muAllContentEncryptionAlgorithm.Unlock() + rebuildContentEncryptionAlgorithm() +} + +func rebuildContentEncryptionAlgorithm() { + list := make([]ContentEncryptionAlgorithm, 0, len(allContentEncryptionAlgorithm)) + muAllContentEncryptionAlgorithm.RLock() + for _, v := range allContentEncryptionAlgorithm { + list = append(list, v) + } + muAllContentEncryptionAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListContentEncryptionAlgorithm.Lock() + listContentEncryptionAlgorithm = list + muListContentEncryptionAlgorithm.Unlock() +} + +// ContentEncryptionAlgorithms returns a list of all available values for ContentEncryptionAlgorithm. +func ContentEncryptionAlgorithms() []ContentEncryptionAlgorithm { + muListContentEncryptionAlgorithm.RLock() + defer muListContentEncryptionAlgorithm.RUnlock() + return listContentEncryptionAlgorithm +} + +// MarshalJSON serializes the ContentEncryptionAlgorithm object to a JSON string. +func (s ContentEncryptionAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a ContentEncryptionAlgorithm object. +func (s *ContentEncryptionAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal ContentEncryptionAlgorithm: %w`, err) + } + v, ok := LookupContentEncryptionAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown ContentEncryptionAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/elliptic_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/elliptic_gen.go new file mode 100644 index 0000000000..2418efde08 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/elliptic_gen.go @@ -0,0 +1,190 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllEllipticCurveAlgorithm sync.RWMutex +var allEllipticCurveAlgorithm = map[string]EllipticCurveAlgorithm{} +var muListEllipticCurveAlgorithm sync.RWMutex +var listEllipticCurveAlgorithm []EllipticCurveAlgorithm +var builtinEllipticCurveAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for EllipticCurveAlgorithm + algorithms := make([]EllipticCurveAlgorithm, 7) + algorithms[0] = NewEllipticCurveAlgorithm("Ed25519") + algorithms[1] = NewEllipticCurveAlgorithm("Ed448") + algorithms[2] = NewEllipticCurveAlgorithm("P-256") + algorithms[3] = NewEllipticCurveAlgorithm("P-384") + algorithms[4] = NewEllipticCurveAlgorithm("P-521") + algorithms[5] = NewEllipticCurveAlgorithm("X25519") + algorithms[6] = NewEllipticCurveAlgorithm("X448") + + RegisterEllipticCurveAlgorithm(algorithms...) +} + +// Ed25519 returns an object representing Ed25519 algorithm for EdDSA operations. +func Ed25519() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("Ed25519") +} + +// Ed448 returns an object representing Ed448 algorithm for EdDSA operations. +func Ed448() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("Ed448") +} + +var invalidEllipticCurve = NewEllipticCurveAlgorithm("P-invalid") + +// InvalidEllipticCurve returns an object representing an invalid elliptic curve. +func InvalidEllipticCurve() EllipticCurveAlgorithm { + return invalidEllipticCurve +} + +// P256 returns an object representing P-256 algorithm for ECDSA operations. +func P256() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("P-256") +} + +// P384 returns an object representing P-384 algorithm for ECDSA operations. +func P384() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("P-384") +} + +// P521 returns an object representing P-521 algorithm for ECDSA operations. +func P521() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("P-521") +} + +// X25519 returns an object representing X25519 algorithm for ECDH operations. +func X25519() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("X25519") +} + +// X448 returns an object representing X448 algorithm for ECDH operations. +func X448() EllipticCurveAlgorithm { + return lookupBuiltinEllipticCurveAlgorithm("X448") +} + +func lookupBuiltinEllipticCurveAlgorithm(name string) EllipticCurveAlgorithm { + muAllEllipticCurveAlgorithm.RLock() + v, ok := allEllipticCurveAlgorithm[name] + muAllEllipticCurveAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: EllipticCurveAlgorithm %q not registered`, name)) + } + return v +} + +// EllipticCurveAlgorithm represents the algorithms used for EC keys +type EllipticCurveAlgorithm struct { + name string + deprecated bool +} + +func (s EllipticCurveAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the EllipticCurveAlgorithm object is deprecated. +func (s EllipticCurveAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// EmptyEllipticCurveAlgorithm returns an empty EllipticCurveAlgorithm object, used as a zero value. +func EmptyEllipticCurveAlgorithm() EllipticCurveAlgorithm { + return EllipticCurveAlgorithm{} +} + +// NewEllipticCurveAlgorithm creates a new EllipticCurveAlgorithm object with the given name. +func NewEllipticCurveAlgorithm(name string, options ...NewAlgorithmOption) EllipticCurveAlgorithm { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewEllipticCurveAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return EllipticCurveAlgorithm{name: name, deprecated: deprecated} +} + +// LookupEllipticCurveAlgorithm returns the EllipticCurveAlgorithm object for the given name. +func LookupEllipticCurveAlgorithm(name string) (EllipticCurveAlgorithm, bool) { + muAllEllipticCurveAlgorithm.RLock() + v, ok := allEllipticCurveAlgorithm[name] + muAllEllipticCurveAlgorithm.RUnlock() + return v, ok +} + +// RegisterEllipticCurveAlgorithm registers a new EllipticCurveAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterEllipticCurveAlgorithm(algorithms ...EllipticCurveAlgorithm) { + muAllEllipticCurveAlgorithm.Lock() + for _, alg := range algorithms { + allEllipticCurveAlgorithm[alg.String()] = alg + } + muAllEllipticCurveAlgorithm.Unlock() + rebuildEllipticCurveAlgorithm() +} + +// UnregisterEllipticCurveAlgorithm unregisters a EllipticCurveAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterEllipticCurveAlgorithm(algorithms ...EllipticCurveAlgorithm) { + muAllEllipticCurveAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinEllipticCurveAlgorithm[alg.String()]; ok { + continue + } + delete(allEllipticCurveAlgorithm, alg.String()) + } + muAllEllipticCurveAlgorithm.Unlock() + rebuildEllipticCurveAlgorithm() +} + +func rebuildEllipticCurveAlgorithm() { + list := make([]EllipticCurveAlgorithm, 0, len(allEllipticCurveAlgorithm)) + muAllEllipticCurveAlgorithm.RLock() + for _, v := range allEllipticCurveAlgorithm { + list = append(list, v) + } + muAllEllipticCurveAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListEllipticCurveAlgorithm.Lock() + listEllipticCurveAlgorithm = list + muListEllipticCurveAlgorithm.Unlock() +} + +// EllipticCurveAlgorithms returns a list of all available values for EllipticCurveAlgorithm. +func EllipticCurveAlgorithms() []EllipticCurveAlgorithm { + muListEllipticCurveAlgorithm.RLock() + defer muListEllipticCurveAlgorithm.RUnlock() + return listEllipticCurveAlgorithm +} + +// MarshalJSON serializes the EllipticCurveAlgorithm object to a JSON string. +func (s EllipticCurveAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a EllipticCurveAlgorithm object. +func (s *EllipticCurveAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal EllipticCurveAlgorithm: %w`, err) + } + v, ok := LookupEllipticCurveAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown EllipticCurveAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/jwa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/jwa.go new file mode 100644 index 0000000000..29ac1dfe76 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/jwa.go @@ -0,0 +1,68 @@ +//go:generate ../tools/cmd/genjwa.sh + +// Package jwa defines the various algorithm described in https://tools.ietf.org/html/rfc7518 +package jwa + +import ( + "errors" + "fmt" +) + +// KeyAlgorithm is a workaround for jwk.Key being able to contain different +// types of algorithms in its `alg` field. +// +// Previously the storage for the `alg` field was represented as a string, +// but this caused some users to wonder why the field was not typed appropriately +// like other fields. +// +// Ideally we would like to keep track of Signature Algorithms and +// Key Encryption Algorithms separately, and force the APIs to +// type-check at compile time, but this allows users to pass a value from a +// jwk.Key directly +type KeyAlgorithm interface { + String() string + IsDeprecated() bool +} + +var errInvalidKeyAlgorithm = errors.New(`invalid key algorithm`) + +func ErrInvalidKeyAlgorithm() error { + return errInvalidKeyAlgorithm +} + +// KeyAlgorithmFrom takes either a string, `jwa.SignatureAlgorithm`, +// `jwa.KeyEncryptionAlgorithm`, or `jwa.ContentEncryptionAlgorithm`. +// and returns a `jwa.KeyAlgorithm`. +// +// If the value cannot be handled, it returns an `jwa.InvalidKeyAlgorithm` +// object instead of returning an error. This design choice was made to allow +// users to directly pass the return value to functions such as `jws.Sign()` +func KeyAlgorithmFrom(v any) (KeyAlgorithm, error) { + switch v := v.(type) { + case SignatureAlgorithm: + return v, nil + case KeyEncryptionAlgorithm: + return v, nil + case ContentEncryptionAlgorithm: + return v, nil + case string: + salg, ok := LookupSignatureAlgorithm(v) + if ok { + return salg, nil + } + + kalg, ok := LookupKeyEncryptionAlgorithm(v) + if ok { + return kalg, nil + } + + calg, ok := LookupContentEncryptionAlgorithm(v) + if ok { + return calg, nil + } + + return nil, fmt.Errorf(`invalid key value: %q: %w`, v, errInvalidKeyAlgorithm) + default: + return nil, fmt.Errorf(`invalid key type: %T: %w`, v, errInvalidKeyAlgorithm) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_encryption_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_encryption_gen.go new file mode 100644 index 0000000000..716c43cd04 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_encryption_gen.go @@ -0,0 +1,268 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +var muAllKeyEncryptionAlgorithm sync.RWMutex +var allKeyEncryptionAlgorithm = map[string]KeyEncryptionAlgorithm{} +var muListKeyEncryptionAlgorithm sync.RWMutex +var listKeyEncryptionAlgorithm []KeyEncryptionAlgorithm +var builtinKeyEncryptionAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for KeyEncryptionAlgorithm + algorithms := make([]KeyEncryptionAlgorithm, 19) + algorithms[0] = NewKeyEncryptionAlgorithm(tokens.A128GCMKW, WithIsSymmetric(true)) + algorithms[1] = NewKeyEncryptionAlgorithm(tokens.A128KW, WithIsSymmetric(true)) + algorithms[2] = NewKeyEncryptionAlgorithm(tokens.A192GCMKW, WithIsSymmetric(true)) + algorithms[3] = NewKeyEncryptionAlgorithm(tokens.A192KW, WithIsSymmetric(true)) + algorithms[4] = NewKeyEncryptionAlgorithm(tokens.A256GCMKW, WithIsSymmetric(true)) + algorithms[5] = NewKeyEncryptionAlgorithm(tokens.A256KW, WithIsSymmetric(true)) + algorithms[6] = NewKeyEncryptionAlgorithm(tokens.DIRECT, WithIsSymmetric(true)) + algorithms[7] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES) + algorithms[8] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A128KW) + algorithms[9] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A192KW) + algorithms[10] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A256KW) + algorithms[11] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS256_A128KW, WithIsSymmetric(true)) + algorithms[12] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS384_A192KW, WithIsSymmetric(true)) + algorithms[13] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS512_A256KW, WithIsSymmetric(true)) + algorithms[14] = NewKeyEncryptionAlgorithm(tokens.RSA1_5, WithDeprecated(true)) + algorithms[15] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP) + algorithms[16] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_256) + algorithms[17] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_384) + algorithms[18] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_512) + + RegisterKeyEncryptionAlgorithm(algorithms...) +} + +// A128GCMKW returns an object representing AES-GCM key wrap (128) key encryption algorithm. +func A128GCMKW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A128GCMKW) +} + +// A128KW returns an object representing AES key wrap (128) key encryption algorithm. +func A128KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A128KW) +} + +// A192GCMKW returns an object representing AES-GCM key wrap (192) key encryption algorithm. +func A192GCMKW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A192GCMKW) +} + +// A192KW returns an object representing AES key wrap (192) key encryption algorithm. +func A192KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A192KW) +} + +// A256GCMKW returns an object representing AES-GCM key wrap (256) key encryption algorithm. +func A256GCMKW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A256GCMKW) +} + +// A256KW returns an object representing AES key wrap (256) key encryption algorithm. +func A256KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.A256KW) +} + +// DIRECT returns an object representing Direct key encryption algorithm. +func DIRECT() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.DIRECT) +} + +// ECDH_ES returns an object representing ECDH-ES key encryption algorithm. +func ECDH_ES() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES) +} + +// ECDH_ES_A128KW returns an object representing ECDH-ES + AES key wrap (128) key encryption algorithm. +func ECDH_ES_A128KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A128KW) +} + +// ECDH_ES_A192KW returns an object representing ECDH-ES + AES key wrap (192) key encryption algorithm. +func ECDH_ES_A192KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A192KW) +} + +// ECDH_ES_A256KW returns an object representing ECDH-ES + AES key wrap (256) key encryption algorithm. +func ECDH_ES_A256KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A256KW) +} + +// PBES2_HS256_A128KW returns an object representing PBES2 + HMAC-SHA256 + AES key wrap (128) key encryption algorithm. +func PBES2_HS256_A128KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS256_A128KW) +} + +// PBES2_HS384_A192KW returns an object representing PBES2 + HMAC-SHA384 + AES key wrap (192) key encryption algorithm. +func PBES2_HS384_A192KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS384_A192KW) +} + +// PBES2_HS512_A256KW returns an object representing PBES2 + HMAC-SHA512 + AES key wrap (256) key encryption algorithm. +func PBES2_HS512_A256KW() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS512_A256KW) +} + +// RSA1_5 returns an object representing RSA-PKCS1v1.5 key encryption algorithm. +func RSA1_5() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA1_5) +} + +// RSA_OAEP returns an object representing RSA-OAEP-SHA1 key encryption algorithm. +func RSA_OAEP() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP) +} + +// RSA_OAEP_256 returns an object representing RSA-OAEP-SHA256 key encryption algorithm. +func RSA_OAEP_256() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_256) +} + +// RSA_OAEP_384 returns an object representing RSA-OAEP-SHA384 key encryption algorithm. +func RSA_OAEP_384() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_384) +} + +// RSA_OAEP_512 returns an object representing RSA-OAEP-SHA512 key encryption algorithm. +func RSA_OAEP_512() KeyEncryptionAlgorithm { + return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_512) +} + +func lookupBuiltinKeyEncryptionAlgorithm(name string) KeyEncryptionAlgorithm { + muAllKeyEncryptionAlgorithm.RLock() + v, ok := allKeyEncryptionAlgorithm[name] + muAllKeyEncryptionAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: KeyEncryptionAlgorithm %q not registered`, name)) + } + return v +} + +// KeyEncryptionAlgorithm represents the various encryption algorithms as described in https://tools.ietf.org/html/rfc7518#section-4.1 +type KeyEncryptionAlgorithm struct { + name string + deprecated bool + isSymmetric bool +} + +func (s KeyEncryptionAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the KeyEncryptionAlgorithm object is deprecated. +func (s KeyEncryptionAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// IsSymmetric returns true if the KeyEncryptionAlgorithm object is symmetric. Symmetric algorithms use the same key for both encryption and decryption. +func (s KeyEncryptionAlgorithm) IsSymmetric() bool { + return s.isSymmetric +} + +// EmptyKeyEncryptionAlgorithm returns an empty KeyEncryptionAlgorithm object, used as a zero value. +func EmptyKeyEncryptionAlgorithm() KeyEncryptionAlgorithm { + return KeyEncryptionAlgorithm{} +} + +// NewKeyEncryptionAlgorithm creates a new KeyEncryptionAlgorithm object with the given name. +func NewKeyEncryptionAlgorithm(name string, options ...NewKeyEncryptionAlgorithmOption) KeyEncryptionAlgorithm { + var deprecated bool + var isSymmetric bool + for _, option := range options { + switch option.Ident() { + case identIsSymmetric{}: + if err := option.Value(&isSymmetric); err != nil { + panic("jwa.NewKeyEncryptionAlgorithm: WithIsSymmetric option must be a boolean") + } + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewKeyEncryptionAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return KeyEncryptionAlgorithm{name: name, deprecated: deprecated, isSymmetric: isSymmetric} +} + +// LookupKeyEncryptionAlgorithm returns the KeyEncryptionAlgorithm object for the given name. +func LookupKeyEncryptionAlgorithm(name string) (KeyEncryptionAlgorithm, bool) { + muAllKeyEncryptionAlgorithm.RLock() + v, ok := allKeyEncryptionAlgorithm[name] + muAllKeyEncryptionAlgorithm.RUnlock() + return v, ok +} + +// RegisterKeyEncryptionAlgorithm registers a new KeyEncryptionAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterKeyEncryptionAlgorithm(algorithms ...KeyEncryptionAlgorithm) { + muAllKeyEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + allKeyEncryptionAlgorithm[alg.String()] = alg + } + muAllKeyEncryptionAlgorithm.Unlock() + rebuildKeyEncryptionAlgorithm() +} + +// UnregisterKeyEncryptionAlgorithm unregisters a KeyEncryptionAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterKeyEncryptionAlgorithm(algorithms ...KeyEncryptionAlgorithm) { + muAllKeyEncryptionAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinKeyEncryptionAlgorithm[alg.String()]; ok { + continue + } + delete(allKeyEncryptionAlgorithm, alg.String()) + } + muAllKeyEncryptionAlgorithm.Unlock() + rebuildKeyEncryptionAlgorithm() +} + +func rebuildKeyEncryptionAlgorithm() { + list := make([]KeyEncryptionAlgorithm, 0, len(allKeyEncryptionAlgorithm)) + muAllKeyEncryptionAlgorithm.RLock() + for _, v := range allKeyEncryptionAlgorithm { + list = append(list, v) + } + muAllKeyEncryptionAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListKeyEncryptionAlgorithm.Lock() + listKeyEncryptionAlgorithm = list + muListKeyEncryptionAlgorithm.Unlock() +} + +// KeyEncryptionAlgorithms returns a list of all available values for KeyEncryptionAlgorithm. +func KeyEncryptionAlgorithms() []KeyEncryptionAlgorithm { + muListKeyEncryptionAlgorithm.RLock() + defer muListKeyEncryptionAlgorithm.RUnlock() + return listKeyEncryptionAlgorithm +} + +// MarshalJSON serializes the KeyEncryptionAlgorithm object to a JSON string. +func (s KeyEncryptionAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a KeyEncryptionAlgorithm object. +func (s *KeyEncryptionAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal KeyEncryptionAlgorithm: %w`, err) + } + v, ok := LookupKeyEncryptionAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown KeyEncryptionAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_type_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_type_gen.go new file mode 100644 index 0000000000..8bc5ebb5f0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/key_type_gen.go @@ -0,0 +1,172 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllKeyType sync.RWMutex +var allKeyType = map[string]KeyType{} +var muListKeyType sync.RWMutex +var listKeyType []KeyType +var builtinKeyType = map[string]struct{}{} + +func init() { + // builtin values for KeyType + algorithms := make([]KeyType, 4) + algorithms[0] = NewKeyType("EC") + algorithms[1] = NewKeyType("OKP") + algorithms[2] = NewKeyType("oct") + algorithms[3] = NewKeyType("RSA") + + RegisterKeyType(algorithms...) +} + +// EC returns an object representing EC. Elliptic Curve +func EC() KeyType { + return lookupBuiltinKeyType("EC") +} + +var invalidKeyType = NewKeyType("") + +// InvalidKeyType returns an object representing invalid key type. Invalid KeyType +func InvalidKeyType() KeyType { + return invalidKeyType +} + +// OKP returns an object representing OKP. Octet string key pairs +func OKP() KeyType { + return lookupBuiltinKeyType("OKP") +} + +// OctetSeq returns an object representing oct. Octet sequence (used to represent symmetric keys) +func OctetSeq() KeyType { + return lookupBuiltinKeyType("oct") +} + +// RSA returns an object representing RSA. RSA +func RSA() KeyType { + return lookupBuiltinKeyType("RSA") +} + +func lookupBuiltinKeyType(name string) KeyType { + muAllKeyType.RLock() + v, ok := allKeyType[name] + muAllKeyType.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: KeyType %q not registered`, name)) + } + return v +} + +// KeyType represents the key type ("kty") that are supported +type KeyType struct { + name string + deprecated bool +} + +func (s KeyType) String() string { + return s.name +} + +// IsDeprecated returns true if the KeyType object is deprecated. +func (s KeyType) IsDeprecated() bool { + return s.deprecated +} + +// EmptyKeyType returns an empty KeyType object, used as a zero value. +func EmptyKeyType() KeyType { + return KeyType{} +} + +// NewKeyType creates a new KeyType object with the given name. +func NewKeyType(name string, options ...NewAlgorithmOption) KeyType { + var deprecated bool + for _, option := range options { + switch option.Ident() { + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewKeyType: WithDeprecated option must be a boolean") + } + } + } + return KeyType{name: name, deprecated: deprecated} +} + +// LookupKeyType returns the KeyType object for the given name. +func LookupKeyType(name string) (KeyType, bool) { + muAllKeyType.RLock() + v, ok := allKeyType[name] + muAllKeyType.RUnlock() + return v, ok +} + +// RegisterKeyType registers a new KeyType. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterKeyType(algorithms ...KeyType) { + muAllKeyType.Lock() + for _, alg := range algorithms { + allKeyType[alg.String()] = alg + } + muAllKeyType.Unlock() + rebuildKeyType() +} + +// UnregisterKeyType unregisters a KeyType from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterKeyType(algorithms ...KeyType) { + muAllKeyType.Lock() + for _, alg := range algorithms { + if _, ok := builtinKeyType[alg.String()]; ok { + continue + } + delete(allKeyType, alg.String()) + } + muAllKeyType.Unlock() + rebuildKeyType() +} + +func rebuildKeyType() { + list := make([]KeyType, 0, len(allKeyType)) + muAllKeyType.RLock() + for _, v := range allKeyType { + list = append(list, v) + } + muAllKeyType.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListKeyType.Lock() + listKeyType = list + muListKeyType.Unlock() +} + +// KeyTypes returns a list of all available values for KeyType. +func KeyTypes() []KeyType { + muListKeyType.RLock() + defer muListKeyType.RUnlock() + return listKeyType +} + +// MarshalJSON serializes the KeyType object to a JSON string. +func (s KeyType) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a KeyType object. +func (s *KeyType) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal KeyType: %w`, err) + } + v, ok := LookupKeyType(name) + if !ok { + return fmt.Errorf(`unknown KeyType: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options.yaml new file mode 100644 index 0000000000..dd498c680e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options.yaml @@ -0,0 +1,41 @@ +package_name: jwa +output: jwa/options_gen.go +interfaces: + - name: NewAlgorithmOption + methods: + - newSignatureAlgorithmOption + - newKeyEncryptionAlgorithmOption + - newSignatureKeyEncryptionAlgorithmOption + comment: | + NewAlgorithmOption represents an option that can be passed to any of the constructor functions + - name: NewSignatureAlgorithmOption + methods: + - newSignatureAlgorithmOption + comment: | + NewSignatureAlgorithmOption represents an option that can be passed to the NewSignatureAlgorithm + - name: NewKeyEncryptionAlgorithmOption + methods: + - newKeyEncryptionAlgorithmOption + comment: | + NewKeyEncryptionAlgorithmOption represents an option that can be passed to the NewKeyEncryptionAlgorithm + - name: NewSignatureKeyEncryptionAlgorithmOption + comment: | + NewSignatureKeyEncryptionAlgorithmOption represents an option that can be passed to both + NewSignatureAlgorithm and NewKeyEncryptionAlgorithm + methods: + - newSignatureAlgorithmOption + - newKeyEncryptionAlgorithmOption +options: + - ident: IsSymmetric + interface: NewSignatureKeyEncryptionAlgorithmOption + argument_type: bool + comment: | + IsSymmetric specifies that the algorithm is symmetric + - ident: Deprecated + interface: NewAlgorithmOption + argument_type: bool + comment: | + WithDeprecated specifies that the algorithm is deprecated. In order to + un-deprecate an algorithm, you will have to create a new algorithm + with the same values but with the Deprecated option set to false, and + then call RegisterXXXXAlgorithm with the new algorithm. \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options_gen.go new file mode 100644 index 0000000000..9394ac587a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/options_gen.go @@ -0,0 +1,91 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwa + +import ( + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// NewAlgorithmOption represents an option that can be passed to any of the constructor functions +type NewAlgorithmOption interface { + Option + newSignatureAlgorithmOption() + newKeyEncryptionAlgorithmOption() + newSignatureKeyEncryptionAlgorithmOption() +} + +type newAlgorithmOption struct { + Option +} + +func (*newAlgorithmOption) newSignatureAlgorithmOption() {} + +func (*newAlgorithmOption) newKeyEncryptionAlgorithmOption() {} + +func (*newAlgorithmOption) newSignatureKeyEncryptionAlgorithmOption() {} + +// NewKeyEncryptionAlgorithmOption represents an option that can be passed to the NewKeyEncryptionAlgorithm +type NewKeyEncryptionAlgorithmOption interface { + Option + newKeyEncryptionAlgorithmOption() +} + +type newKeyEncryptionAlgorithmOption struct { + Option +} + +func (*newKeyEncryptionAlgorithmOption) newKeyEncryptionAlgorithmOption() {} + +// NewSignatureAlgorithmOption represents an option that can be passed to the NewSignatureAlgorithm +type NewSignatureAlgorithmOption interface { + Option + newSignatureAlgorithmOption() +} + +type newSignatureAlgorithmOption struct { + Option +} + +func (*newSignatureAlgorithmOption) newSignatureAlgorithmOption() {} + +// NewSignatureKeyEncryptionAlgorithmOption represents an option that can be passed to both +// NewSignatureAlgorithm and NewKeyEncryptionAlgorithm +type NewSignatureKeyEncryptionAlgorithmOption interface { + Option + newSignatureAlgorithmOption() + newKeyEncryptionAlgorithmOption() +} + +type newSignatureKeyEncryptionAlgorithmOption struct { + Option +} + +func (*newSignatureKeyEncryptionAlgorithmOption) newSignatureAlgorithmOption() {} + +func (*newSignatureKeyEncryptionAlgorithmOption) newKeyEncryptionAlgorithmOption() {} + +type identDeprecated struct{} +type identIsSymmetric struct{} + +func (identDeprecated) String() string { + return "WithDeprecated" +} + +func (identIsSymmetric) String() string { + return "WithIsSymmetric" +} + +// WithDeprecated specifies that the algorithm is deprecated. In order to +// un-deprecate an algorithm, you will have to create a new algorithm +// with the same values but with the Deprecated option set to false, and +// then call RegisterXXXXAlgorithm with the new algorithm. +func WithDeprecated(v bool) NewAlgorithmOption { + return &newAlgorithmOption{option.New(identDeprecated{}, v)} +} + +// IsSymmetric specifies that the algorithm is symmetric +func WithIsSymmetric(v bool) NewSignatureKeyEncryptionAlgorithmOption { + return &newSignatureKeyEncryptionAlgorithmOption{option.New(identIsSymmetric{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/secp2561k.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/secp2561k.go new file mode 100644 index 0000000000..e7a6be754d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/secp2561k.go @@ -0,0 +1,15 @@ +//go:build jwx_es256k +// +build jwx_es256k + +package jwa + +var secp256k1Algorithm = NewEllipticCurveAlgorithm("secp256k1") + +// This constant is only available if compiled with jwx_es256k build tag +func Secp256k1() EllipticCurveAlgorithm { + return secp256k1Algorithm +} + +func init() { + RegisterEllipticCurveAlgorithm(secp256k1Algorithm) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwa/signature_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwa/signature_gen.go new file mode 100644 index 0000000000..653d7d56af --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwa/signature_gen.go @@ -0,0 +1,242 @@ +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "encoding/json" + "fmt" + "sort" + "sync" +) + +var muAllSignatureAlgorithm sync.RWMutex +var allSignatureAlgorithm = map[string]SignatureAlgorithm{} +var muListSignatureAlgorithm sync.RWMutex +var listSignatureAlgorithm []SignatureAlgorithm +var builtinSignatureAlgorithm = map[string]struct{}{} + +func init() { + // builtin values for SignatureAlgorithm + algorithms := make([]SignatureAlgorithm, 15) + algorithms[0] = NewSignatureAlgorithm("ES256") + algorithms[1] = NewSignatureAlgorithm("ES256K") + algorithms[2] = NewSignatureAlgorithm("ES384") + algorithms[3] = NewSignatureAlgorithm("ES512") + algorithms[4] = NewSignatureAlgorithm("EdDSA") + algorithms[5] = NewSignatureAlgorithm("HS256", WithIsSymmetric(true)) + algorithms[6] = NewSignatureAlgorithm("HS384", WithIsSymmetric(true)) + algorithms[7] = NewSignatureAlgorithm("HS512", WithIsSymmetric(true)) + algorithms[8] = NewSignatureAlgorithm("none") + algorithms[9] = NewSignatureAlgorithm("PS256") + algorithms[10] = NewSignatureAlgorithm("PS384") + algorithms[11] = NewSignatureAlgorithm("PS512") + algorithms[12] = NewSignatureAlgorithm("RS256") + algorithms[13] = NewSignatureAlgorithm("RS384") + algorithms[14] = NewSignatureAlgorithm("RS512") + + RegisterSignatureAlgorithm(algorithms...) +} + +// ES256 returns an object representing ECDSA signature algorithm using P-256 curve and SHA-256. +func ES256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES256") +} + +// ES256K returns an object representing ECDSA signature algorithm using secp256k1 curve and SHA-256. +func ES256K() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES256K") +} + +// ES384 returns an object representing ECDSA signature algorithm using P-384 curve and SHA-384. +func ES384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES384") +} + +// ES512 returns an object representing ECDSA signature algorithm using P-521 curve and SHA-512. +func ES512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ES512") +} + +// EdDSA returns an object representing EdDSA signature algorithms. +func EdDSA() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("EdDSA") +} + +// HS256 returns an object representing HMAC signature algorithm using SHA-256. +func HS256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("HS256") +} + +// HS384 returns an object representing HMAC signature algorithm using SHA-384. +func HS384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("HS384") +} + +// HS512 returns an object representing HMAC signature algorithm using SHA-512. +func HS512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("HS512") +} + +// NoSignature returns an object representing the lack of a signature algorithm. Using this value specifies that the content should not be signed, which you should avoid doing. +func NoSignature() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("none") +} + +// PS256 returns an object representing RSASSA-PSS signature algorithm using SHA-256 and MGF1-SHA256. +func PS256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("PS256") +} + +// PS384 returns an object representing RSASSA-PSS signature algorithm using SHA-384 and MGF1-SHA384. +func PS384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("PS384") +} + +// PS512 returns an object representing RSASSA-PSS signature algorithm using SHA-512 and MGF1-SHA512. +func PS512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("PS512") +} + +// RS256 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-256. +func RS256() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("RS256") +} + +// RS384 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-384. +func RS384() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("RS384") +} + +// RS512 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-512. +func RS512() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("RS512") +} + +func lookupBuiltinSignatureAlgorithm(name string) SignatureAlgorithm { + muAllSignatureAlgorithm.RLock() + v, ok := allSignatureAlgorithm[name] + muAllSignatureAlgorithm.RUnlock() + if !ok { + panic(fmt.Sprintf(`jwa: SignatureAlgorithm %q not registered`, name)) + } + return v +} + +// SignatureAlgorithm represents the various signature algorithms as described in https://tools.ietf.org/html/rfc7518#section-3.1 +type SignatureAlgorithm struct { + name string + deprecated bool + isSymmetric bool +} + +func (s SignatureAlgorithm) String() string { + return s.name +} + +// IsDeprecated returns true if the SignatureAlgorithm object is deprecated. +func (s SignatureAlgorithm) IsDeprecated() bool { + return s.deprecated +} + +// IsSymmetric returns true if the SignatureAlgorithm object is symmetric. Symmetric algorithms use the same key for both encryption and decryption. +func (s SignatureAlgorithm) IsSymmetric() bool { + return s.isSymmetric +} + +// EmptySignatureAlgorithm returns an empty SignatureAlgorithm object, used as a zero value. +func EmptySignatureAlgorithm() SignatureAlgorithm { + return SignatureAlgorithm{} +} + +// NewSignatureAlgorithm creates a new SignatureAlgorithm object with the given name. +func NewSignatureAlgorithm(name string, options ...NewSignatureAlgorithmOption) SignatureAlgorithm { + var deprecated bool + var isSymmetric bool + for _, option := range options { + switch option.Ident() { + case identIsSymmetric{}: + if err := option.Value(&isSymmetric); err != nil { + panic("jwa.NewSignatureAlgorithm: WithIsSymmetric option must be a boolean") + } + case identDeprecated{}: + if err := option.Value(&deprecated); err != nil { + panic("jwa.NewSignatureAlgorithm: WithDeprecated option must be a boolean") + } + } + } + return SignatureAlgorithm{name: name, deprecated: deprecated, isSymmetric: isSymmetric} +} + +// LookupSignatureAlgorithm returns the SignatureAlgorithm object for the given name. +func LookupSignatureAlgorithm(name string) (SignatureAlgorithm, bool) { + muAllSignatureAlgorithm.RLock() + v, ok := allSignatureAlgorithm[name] + muAllSignatureAlgorithm.RUnlock() + return v, ok +} + +// RegisterSignatureAlgorithm registers a new SignatureAlgorithm. The signature value must be immutable +// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library. +func RegisterSignatureAlgorithm(algorithms ...SignatureAlgorithm) { + muAllSignatureAlgorithm.Lock() + for _, alg := range algorithms { + allSignatureAlgorithm[alg.String()] = alg + } + muAllSignatureAlgorithm.Unlock() + rebuildSignatureAlgorithm() +} + +// UnregisterSignatureAlgorithm unregisters a SignatureAlgorithm from its known database. +// Non-existent entries, as well as built-in algorithms will silently be ignored. +func UnregisterSignatureAlgorithm(algorithms ...SignatureAlgorithm) { + muAllSignatureAlgorithm.Lock() + for _, alg := range algorithms { + if _, ok := builtinSignatureAlgorithm[alg.String()]; ok { + continue + } + delete(allSignatureAlgorithm, alg.String()) + } + muAllSignatureAlgorithm.Unlock() + rebuildSignatureAlgorithm() +} + +func rebuildSignatureAlgorithm() { + list := make([]SignatureAlgorithm, 0, len(allSignatureAlgorithm)) + muAllSignatureAlgorithm.RLock() + for _, v := range allSignatureAlgorithm { + list = append(list, v) + } + muAllSignatureAlgorithm.RUnlock() + sort.Slice(list, func(i, j int) bool { + return list[i].String() < list[j].String() + }) + muListSignatureAlgorithm.Lock() + listSignatureAlgorithm = list + muListSignatureAlgorithm.Unlock() +} + +// SignatureAlgorithms returns a list of all available values for SignatureAlgorithm. +func SignatureAlgorithms() []SignatureAlgorithm { + muListSignatureAlgorithm.RLock() + defer muListSignatureAlgorithm.RUnlock() + return listSignatureAlgorithm +} + +// MarshalJSON serializes the SignatureAlgorithm object to a JSON string. +func (s SignatureAlgorithm) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON deserializes the JSON string to a SignatureAlgorithm object. +func (s *SignatureAlgorithm) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return fmt.Errorf(`failed to unmarshal SignatureAlgorithm: %w`, err) + } + v, ok := LookupSignatureAlgorithm(name) + if !ok { + return fmt.Errorf(`unknown SignatureAlgorithm: %q`, name) + } + *s = v + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/BUILD.bazel new file mode 100644 index 0000000000..0719efd2dc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/BUILD.bazel @@ -0,0 +1,70 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwe", + srcs = [ + "compress.go", + "decrypt.go", + "encrypt.go", + "errors.go", + "filter.go", + "headers.go", + "headers_gen.go", + "interface.go", + "io.go", + "jwe.go", + "key_provider.go", + "message.go", + "options.go", + "options_gen.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe", + visibility = ["//visibility:public"], + deps = [ + "//cert", + "//internal/base64", + "//transform", + "//internal/json", + "//internal/tokens", + "//internal/keyconv", + "//internal/pool", + "//jwa", + "//jwe/internal/aescbc", + "//jwe/internal/cipher", + "//jwe/internal/content_crypt", + "//jwe/internal/keygen", + "//jwe/jwebb", + "//jwk", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_option_v2//:option", + "@org_golang_x_crypto//pbkdf2", + ], +) + +go_test( + name = "jwe_test", + srcs = [ + "filter_test.go", + "gh402_test.go", + "headers_test.go", + "jwe_test.go", + "message_test.go", + "options_gen_test.go", + "speed_test.go", + ], + embed = [":jwe"], + deps = [ + "//cert", + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwk", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwe", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwe/README.md new file mode 100644 index 0000000000..c85d05bbbe --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/README.md @@ -0,0 +1,94 @@ +# JWE [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwe.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwe) + +Package jwe implements JWE as described in [RFC7516](https://tools.ietf.org/html/rfc7516) + +* Encrypt and Decrypt arbitrary data +* Content compression and decompression +* Add arbitrary fields in the JWE header object + +How-to style documentation can be found in the [docs directory](../docs). + +Examples are located in the examples directory ([jwe_example_test.go](../examples/jwe_example_test.go)) + +Supported key encryption algorithm: + +| Algorithm | Supported? | Constant in [jwa](../jwa) | +|:-----------------------------------------|:-----------|:-------------------------| +| RSA-PKCS1v1.5 | YES | jwa.RSA1_5 | +| RSA-OAEP-SHA1 | YES | jwa.RSA_OAEP | +| RSA-OAEP-SHA256 | YES | jwa.RSA_OAEP_256 | +| AES key wrap (128) | YES | jwa.A128KW | +| AES key wrap (192) | YES | jwa.A192KW | +| AES key wrap (256) | YES | jwa.A256KW | +| Direct encryption | YES (1) | jwa.DIRECT | +| ECDH-ES | YES (1) | jwa.ECDH_ES | +| ECDH-ES + AES key wrap (128) | YES | jwa.ECDH_ES_A128KW | +| ECDH-ES + AES key wrap (192) | YES | jwa.ECDH_ES_A192KW | +| ECDH-ES + AES key wrap (256) | YES | jwa.ECDH_ES_A256KW | +| AES-GCM key wrap (128) | YES | jwa.A128GCMKW | +| AES-GCM key wrap (192) | YES | jwa.A192GCMKW | +| AES-GCM key wrap (256) | YES | jwa.A256GCMKW | +| PBES2 + HMAC-SHA256 + AES key wrap (128) | YES | jwa.PBES2_HS256_A128KW | +| PBES2 + HMAC-SHA384 + AES key wrap (192) | YES | jwa.PBES2_HS384_A192KW | +| PBES2 + HMAC-SHA512 + AES key wrap (256) | YES | jwa.PBES2_HS512_A256KW | + +* Note 1: Single-recipient only + +Supported content encryption algorithm: + +| Algorithm | Supported? | Constant in [jwa](../jwa) | +|:----------------------------|:-----------|:--------------------------| +| AES-CBC + HMAC-SHA256 (128) | YES | jwa.A128CBC_HS256 | +| AES-CBC + HMAC-SHA384 (192) | YES | jwa.A192CBC_HS384 | +| AES-CBC + HMAC-SHA512 (256) | YES | jwa.A256CBC_HS512 | +| AES-GCM (128) | YES | jwa.A128GCM | +| AES-GCM (192) | YES | jwa.A192GCM | +| AES-GCM (256) | YES | jwa.A256GCM | + +# SYNOPSIS + +## Encrypt data + +```go +func ExampleEncrypt() { + privkey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Printf("failed to generate private key: %s", err) + return + } + + payload := []byte("Lorem Ipsum") + + encrypted, err := jwe.Encrypt(payload, jwe.WithKey(jwa.RSA1_5, &privkey.PublicKey), jwe.WithContentEncryption(jwa.A128CBC_HS256)) + if err != nil { + log.Printf("failed to encrypt payload: %s", err) + return + } + _ = encrypted + // OUTPUT: +} +``` + +## Decrypt data + +```go +func ExampleDecrypt() { + privkey, encrypted, err := exampleGenPayload() + if err != nil { + log.Printf("failed to generate encrypted payload: %s", err) + return + } + + decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA1_5, privkey)) + if err != nil { + log.Printf("failed to decrypt: %s", err) + return + } + + if string(decrypted) != "Lorem Ipsum" { + log.Printf("WHAT?!") + return + } + // OUTPUT: +} +``` diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/compress.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/compress.go new file mode 100644 index 0000000000..a1ed158fb0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/compress.go @@ -0,0 +1,62 @@ +package jwe + +import ( + "bytes" + "compress/flate" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/pool" +) + +func uncompress(src []byte, maxBufferSize int64) ([]byte, error) { + var dst bytes.Buffer + r := flate.NewReader(bytes.NewReader(src)) + defer r.Close() + var buf [16384]byte + var sofar int64 + for { + n, readErr := r.Read(buf[:]) + sofar += int64(n) + if sofar > maxBufferSize { + return nil, fmt.Errorf(`compressed payload exceeds maximum allowed size`) + } + if readErr != nil { + // if we have a read error, and it's not EOF, then we need to stop + if readErr != io.EOF { + return nil, fmt.Errorf(`failed to read inflated data: %w`, readErr) + } + } + + if _, err := dst.Write(buf[:n]); err != nil { + return nil, fmt.Errorf(`failed to write inflated data: %w`, err) + } + + if readErr != nil { + // if it got here, then readErr == io.EOF, we're done + return dst.Bytes(), nil + } + } +} + +func compress(plaintext []byte) ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + w, _ := flate.NewWriter(buf, 1) + in := plaintext + for len(in) > 0 { + n, err := w.Write(in) + if err != nil { + return nil, fmt.Errorf(`failed to write to compression writer: %w`, err) + } + in = in[n:] + } + if err := w.Close(); err != nil { + return nil, fmt.Errorf(`failed to close compression writer: %w`, err) + } + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/decrypt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/decrypt.go new file mode 100644 index 0000000000..9429d84b1b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/decrypt.go @@ -0,0 +1,227 @@ +package jwe + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" + "github.com/lestrrat-go/jwx/v3/jwe/jwebb" +) + +// decrypter is responsible for taking various components to decrypt a message. +// its operation is not concurrency safe. You must provide locking yourself +// +//nolint:govet +type decrypter struct { + aad []byte + apu []byte + apv []byte + cek *[]byte + computedAad []byte + iv []byte + keyiv []byte + keysalt []byte + keytag []byte + tag []byte + privkey any + pubkey any + ctalg jwa.ContentEncryptionAlgorithm + keyalg jwa.KeyEncryptionAlgorithm + cipher content_crypt.Cipher + keycount int +} + +// newDecrypter Creates a new Decrypter instance. You must supply the +// rest of parameters via their respective setter methods before +// calling Decrypt(). +// +// privkey must be a private key in its "raw" format (i.e. something like +// *rsa.PrivateKey, instead of jwk.Key) +// +// You should consider this object immutable once you assign values to it. +func newDecrypter(keyalg jwa.KeyEncryptionAlgorithm, ctalg jwa.ContentEncryptionAlgorithm, privkey any) *decrypter { + return &decrypter{ + ctalg: ctalg, + keyalg: keyalg, + privkey: privkey, + } +} + +func (d *decrypter) AgreementPartyUInfo(apu []byte) *decrypter { + d.apu = apu + return d +} + +func (d *decrypter) AgreementPartyVInfo(apv []byte) *decrypter { + d.apv = apv + return d +} + +func (d *decrypter) AuthenticatedData(aad []byte) *decrypter { + d.aad = aad + return d +} + +func (d *decrypter) ComputedAuthenticatedData(aad []byte) *decrypter { + d.computedAad = aad + return d +} + +func (d *decrypter) ContentEncryptionAlgorithm(ctalg jwa.ContentEncryptionAlgorithm) *decrypter { + d.ctalg = ctalg + return d +} + +func (d *decrypter) InitializationVector(iv []byte) *decrypter { + d.iv = iv + return d +} + +func (d *decrypter) KeyCount(keycount int) *decrypter { + d.keycount = keycount + return d +} + +func (d *decrypter) KeyInitializationVector(keyiv []byte) *decrypter { + d.keyiv = keyiv + return d +} + +func (d *decrypter) KeySalt(keysalt []byte) *decrypter { + d.keysalt = keysalt + return d +} + +func (d *decrypter) KeyTag(keytag []byte) *decrypter { + d.keytag = keytag + return d +} + +// PublicKey sets the public key to be used in decoding EC based encryptions. +// The key must be in its "raw" format (i.e. *ecdsa.PublicKey, instead of jwk.Key) +func (d *decrypter) PublicKey(pubkey any) *decrypter { + d.pubkey = pubkey + return d +} + +func (d *decrypter) Tag(tag []byte) *decrypter { + d.tag = tag + return d +} + +func (d *decrypter) CEK(ptr *[]byte) *decrypter { + d.cek = ptr + return d +} + +func (d *decrypter) ContentCipher() (content_crypt.Cipher, error) { + if d.cipher == nil { + cipher, err := jwebb.CreateContentCipher(d.ctalg.String()) + if err != nil { + return nil, err + } + d.cipher = cipher + } + + return d.cipher, nil +} + +func (d *decrypter) Decrypt(recipient Recipient, ciphertext []byte, msg *Message) (plaintext []byte, err error) { + cek, keyerr := d.DecryptKey(recipient, msg) + if keyerr != nil { + err = fmt.Errorf(`failed to decrypt key: %w`, keyerr) + return + } + + cipher, ciphererr := d.ContentCipher() + if ciphererr != nil { + err = fmt.Errorf(`failed to fetch content crypt cipher: %w`, ciphererr) + return + } + + computedAad := d.computedAad + if d.aad != nil { + computedAad = append(append(computedAad, tokens.Period), d.aad...) + } + + plaintext, err = cipher.Decrypt(cek, d.iv, ciphertext, d.tag, computedAad) + if err != nil { + err = fmt.Errorf(`failed to decrypt payload: %w`, err) + return + } + + if d.cek != nil { + *d.cek = cek + } + return plaintext, nil +} + +func (d *decrypter) DecryptKey(recipient Recipient, msg *Message) (cek []byte, err error) { + recipientKey := recipient.EncryptedKey() + if kd, ok := d.privkey.(KeyDecrypter); ok { + return kd.DecryptKey(d.keyalg, recipientKey, recipient, msg) + } + + if jwebb.IsDirect(d.keyalg.String()) { + cek, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("decrypt key: []byte is required as the key for %s (got %T)", d.keyalg, d.privkey) + } + return jwebb.KeyDecryptDirect(recipientKey, recipientKey, d.keyalg.String(), cek) + } + + if jwebb.IsPBES2(d.keyalg.String()) { + password, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("decrypt key: []byte is required as the password for %s (got %T)", d.keyalg, d.privkey) + } + salt := []byte(d.keyalg.String()) + salt = append(salt, byte(0)) + salt = append(salt, d.keysalt...) + return jwebb.KeyDecryptPBES2(recipientKey, recipientKey, d.keyalg.String(), password, salt, d.keycount) + } + + if jwebb.IsAESGCMKW(d.keyalg.String()) { + sharedkey, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("decrypt key: []byte is required as the key for %s (got %T)", d.keyalg, d.privkey) + } + return jwebb.KeyDecryptAESGCMKW(recipientKey, recipientKey, d.keyalg.String(), sharedkey, d.keyiv, d.keytag) + } + + if jwebb.IsECDHES(d.keyalg.String()) { + alg, keysize, keywrap, err := jwebb.KeyEncryptionECDHESKeySize(d.keyalg.String(), d.ctalg.String()) + if err != nil { + return nil, fmt.Errorf(`failed to determine ECDH-ES key size: %w`, err) + } + + if !keywrap { + return jwebb.KeyDecryptECDHES(recipientKey, cek, alg, d.apu, d.apv, d.privkey, d.pubkey, keysize) + } + return jwebb.KeyDecryptECDHESKeyWrap(recipientKey, recipientKey, d.keyalg.String(), d.apu, d.apv, d.privkey, d.pubkey, keysize) + } + + if jwebb.IsRSA15(d.keyalg.String()) { + cipher, err := d.ContentCipher() + if err != nil { + return nil, fmt.Errorf(`failed to fetch content crypt cipher: %w`, err) + } + keysize := cipher.KeySize() / 2 + return jwebb.KeyDecryptRSA15(recipientKey, recipientKey, d.privkey, keysize) + } + + if jwebb.IsRSAOAEP(d.keyalg.String()) { + return jwebb.KeyDecryptRSAOAEP(recipientKey, recipientKey, d.keyalg.String(), d.privkey) + } + + if jwebb.IsAESKW(d.keyalg.String()) { + sharedkey, ok := d.privkey.([]byte) + if !ok { + return nil, fmt.Errorf("[]byte is required as the key to decrypt %s", d.keyalg.String()) + } + return jwebb.KeyDecryptAESKW(recipientKey, recipientKey, d.keyalg.String(), sharedkey) + } + + return nil, fmt.Errorf(`unsupported algorithm for key decryption (%s)`, d.keyalg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/encrypt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/encrypt.go new file mode 100644 index 0000000000..a71e71689a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/encrypt.go @@ -0,0 +1,168 @@ +package jwe + +import ( + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" + "github.com/lestrrat-go/jwx/v3/jwe/jwebb" +) + +// encrypter is responsible for taking various components to encrypt a key. +// its operation is not concurrency safe. You must provide locking yourself +// +//nolint:govet +type encrypter struct { + apu []byte + apv []byte + ctalg jwa.ContentEncryptionAlgorithm + keyalg jwa.KeyEncryptionAlgorithm + pubkey any + rawKey any + cipher content_crypt.Cipher +} + +// newEncrypter creates a new Encrypter instance with all required parameters. +// The content cipher is built internally during construction. +// +// pubkey must be a public key in its "raw" format (i.e. something like +// *rsa.PublicKey, instead of jwk.Key) +// +// You should consider this object immutable once created. +func newEncrypter(keyalg jwa.KeyEncryptionAlgorithm, ctalg jwa.ContentEncryptionAlgorithm, pubkey any, rawKey any, apu, apv []byte) (*encrypter, error) { + cipher, err := jwebb.CreateContentCipher(ctalg.String()) + if err != nil { + return nil, fmt.Errorf(`failed to create content cipher: %w`, err) + } + + return &encrypter{ + apu: apu, + apv: apv, + ctalg: ctalg, + keyalg: keyalg, + pubkey: pubkey, + rawKey: rawKey, + cipher: cipher, + }, nil +} + +func (e *encrypter) EncryptKey(cek []byte) (keygen.ByteSource, error) { + if ke, ok := e.pubkey.(KeyEncrypter); ok { + encrypted, err := ke.EncryptKey(cek) + if err != nil { + return nil, err + } + return keygen.ByteKey(encrypted), nil + } + + if jwebb.IsDirect(e.keyalg.String()) { + sharedkey, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("encrypt key: []byte is required as the key for %s (got %T)", e.keyalg, e.rawKey) + } + return jwebb.KeyEncryptDirect(cek, e.keyalg.String(), sharedkey) + } + + if jwebb.IsPBES2(e.keyalg.String()) { + password, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("encrypt key: []byte is required as the password for %s (got %T)", e.keyalg, e.rawKey) + } + return jwebb.KeyEncryptPBES2(cek, e.keyalg.String(), password) + } + + if jwebb.IsAESGCMKW(e.keyalg.String()) { + sharedkey, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("encrypt key: []byte is required as the key for %s (got %T)", e.keyalg, e.rawKey) + } + return jwebb.KeyEncryptAESGCMKW(cek, e.keyalg.String(), sharedkey) + } + + if jwebb.IsECDHES(e.keyalg.String()) { + _, keysize, keywrap, err := jwebb.KeyEncryptionECDHESKeySize(e.keyalg.String(), e.ctalg.String()) + if err != nil { + return nil, fmt.Errorf(`failed to determine ECDH-ES key size: %w`, err) + } + + // Use rawKey for ECDH-ES operations - it should contain the actual key material + keyToUse := e.rawKey + if keyToUse == nil { + keyToUse = e.pubkey + } + + // Handle ecdsa.PublicKey by value - convert to pointer + if pk, ok := keyToUse.(ecdsa.PublicKey); ok { + keyToUse = &pk + } + + // Determine key type and call appropriate function + switch key := keyToUse.(type) { + case *ecdsa.PublicKey: + if !keywrap { + return jwebb.KeyEncryptECDHESECDSA(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + } + return jwebb.KeyEncryptECDHESKeyWrapECDSA(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + case *ecdh.PublicKey: + if !keywrap { + return jwebb.KeyEncryptECDHESX25519(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + } + return jwebb.KeyEncryptECDHESKeyWrapX25519(cek, e.keyalg.String(), e.apu, e.apv, key, keysize, e.ctalg.String()) + default: + return nil, fmt.Errorf(`encrypt: unsupported key type for ECDH-ES: %T`, keyToUse) + } + } + + if jwebb.IsRSA15(e.keyalg.String()) { + keyToUse := e.rawKey + if keyToUse == nil { + keyToUse = e.pubkey + } + + // Handle rsa.PublicKey by value - convert to pointer + if pk, ok := keyToUse.(rsa.PublicKey); ok { + keyToUse = &pk + } + + var pubkey *rsa.PublicKey + if err := keyconv.RSAPublicKey(&pubkey, keyToUse); err != nil { + return nil, fmt.Errorf(`encrypt: failed to convert to RSA public key: %w`, err) + } + + return jwebb.KeyEncryptRSA15(cek, e.keyalg.String(), pubkey) + } + + if jwebb.IsRSAOAEP(e.keyalg.String()) { + keyToUse := e.rawKey + if keyToUse == nil { + keyToUse = e.pubkey + } + + // Handle rsa.PublicKey by value - convert to pointer + if pk, ok := keyToUse.(rsa.PublicKey); ok { + keyToUse = &pk + } + + var pubkey *rsa.PublicKey + if err := keyconv.RSAPublicKey(&pubkey, keyToUse); err != nil { + return nil, fmt.Errorf(`encrypt: failed to convert to RSA public key: %w`, err) + } + + return jwebb.KeyEncryptRSAOAEP(cek, e.keyalg.String(), pubkey) + } + + if jwebb.IsAESKW(e.keyalg.String()) { + sharedkey, ok := e.rawKey.([]byte) + if !ok { + return nil, fmt.Errorf("[]byte is required as the key to encrypt %s", e.keyalg.String()) + } + return jwebb.KeyEncryptAESKW(cek, e.keyalg.String(), sharedkey) + } + + return nil, fmt.Errorf(`unsupported algorithm for key encryption (%s)`, e.keyalg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/errors.go new file mode 100644 index 0000000000..89d276fc44 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/errors.go @@ -0,0 +1,90 @@ +package jwe + +import "errors" + +type encryptError struct { + error +} + +func (e encryptError) Unwrap() error { + return e.error +} + +func (encryptError) Is(err error) bool { + _, ok := err.(encryptError) + return ok +} + +var errDefaultEncryptError = encryptError{errors.New(`encrypt error`)} + +// EncryptError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Encrypt`. +func EncryptError() error { + return errDefaultEncryptError +} + +type decryptError struct { + error +} + +func (e decryptError) Unwrap() error { + return e.error +} + +func (decryptError) Is(err error) bool { + _, ok := err.(decryptError) + return ok +} + +var errDefaultDecryptError = decryptError{errors.New(`decrypt error`)} + +// DecryptError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Decrypt`. +func DecryptError() error { + return errDefaultDecryptError +} + +type recipientError struct { + error +} + +func (e recipientError) Unwrap() error { + return e.error +} + +func (recipientError) Is(err error) bool { + _, ok := err.(recipientError) + return ok +} + +var errDefaultRecipientError = recipientError{errors.New(`recipient error`)} + +// RecipientError returns an error that can be passed to `errors.Is` to check if the error is +// an error that occurred while attempting to decrypt a JWE message for a particular recipient. +// +// For example, if the JWE message failed to parse during `jwe.Decrypt`, it will be a +// `jwe.DecryptError`, but NOT `jwe.RecipientError`. However, if the JWE message could not +// be decrypted for any of the recipients, then it will be a `jwe.RecipientError` +// (actually, it will be _multiple_ `jwe.RecipientError` errors, one for each recipient) +func RecipientError() error { + return errDefaultRecipientError +} + +type parseError struct { + error +} + +func (e parseError) Unwrap() error { + return e.error +} + +func (parseError) Is(err error) bool { + _, ok := err.(parseError) + return ok +} + +var errDefaultParseError = parseError{errors.New(`parse error`)} + +// ParseError returns an error that can be passed to `errors.Is` to check if the error +// is an error returned by `jwe.Parse` and related functions. +func ParseError() error { + return errDefaultParseError +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/filter.go new file mode 100644 index 0000000000..14941604bf --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/filter.go @@ -0,0 +1,36 @@ +package jwe + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// HeaderFilter is an interface that allows users to filter JWE header fields. +// It provides two methods: Filter and Reject; Filter returns a new header with only +// the fields that match the filter criteria, while Reject returns a new header with +// only the fields that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type HeaderFilter interface { + Filter(header Headers) (Headers, error) + Reject(header Headers) (Headers, error) +} + +// StandardHeadersFilter returns a HeaderFilter that filters out standard JWE header fields. +// +// You can use this filter to create headers that either only have standard fields +// or only custom fields. +// +// If you need to configure the filter more precisely, consider +// using the HeaderNameFilter directly. +func StandardHeadersFilter() HeaderFilter { + return stdHeadersFilter +} + +var stdHeadersFilter = NewHeaderNameFilter(stdHeaderNames...) + +// NewHeaderNameFilter creates a new HeaderNameFilter with the specified field names. +func NewHeaderNameFilter(names ...string) HeaderFilter { + return transform.NewNameBasedFilter[Headers](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers.go new file mode 100644 index 0000000000..6e13afde76 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers.go @@ -0,0 +1,95 @@ +package jwe + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +type isZeroer interface { + isZero() bool +} + +func (h *stdHeaders) isZero() bool { + return h.agreementPartyUInfo == nil && + h.agreementPartyVInfo == nil && + h.algorithm == nil && + h.compression == nil && + h.contentEncryption == nil && + h.contentType == nil && + h.critical == nil && + h.ephemeralPublicKey == nil && + h.jwk == nil && + h.jwkSetURL == nil && + h.keyID == nil && + h.typ == nil && + h.x509CertChain == nil && + h.x509CertThumbprint == nil && + h.x509CertThumbprintS256 == nil && + h.x509URL == nil && + len(h.privateParams) == 0 +} + +func (h *stdHeaders) Clone() (Headers, error) { + dst := NewHeaders() + if err := h.Copy(dst); err != nil { + return nil, fmt.Errorf(`failed to copy header contents to new object: %w`, err) + } + return dst, nil +} + +func (h *stdHeaders) Copy(dst Headers) error { + for _, key := range h.Keys() { + var v any + if err := h.Get(key, &v); err != nil { + return fmt.Errorf(`jwe.Headers: Copy: failed to get header %q: %w`, key, err) + } + + if err := dst.Set(key, v); err != nil { + return fmt.Errorf(`jwe.Headers: Copy: failed to set header %q: %w`, key, err) + } + } + return nil +} + +func (h *stdHeaders) Merge(h2 Headers) (Headers, error) { + h3 := NewHeaders() + + if h != nil { + if err := h.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from receiver: %w`, err) + } + } + + if h2 != nil { + if err := h2.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from argument: %w`, err) + } + } + + return h3, nil +} + +func (h *stdHeaders) Encode() ([]byte, error) { + buf, err := json.Marshal(h) + if err != nil { + return nil, fmt.Errorf(`failed to marshal headers to JSON prior to encoding: %w`, err) + } + + return base64.Encode(buf), nil +} + +func (h *stdHeaders) Decode(buf []byte) error { + // base64 json string -> json object representation of header + decoded, err := base64.Decode(buf) + if err != nil { + return fmt.Errorf(`failed to unmarshal base64 encoded buffer: %w`, err) + } + + if err := json.Unmarshal(decoded, h); err != nil { + return fmt.Errorf(`failed to unmarshal buffer: %w`, err) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers_gen.go new file mode 100644 index 0000000000..7773a5d812 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/headers_gen.go @@ -0,0 +1,899 @@ +// Code generated by tools/cmd/genjwe/main.go. DO NOT EDIT. + +package jwe + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +const ( + AgreementPartyUInfoKey = "apu" + AgreementPartyVInfoKey = "apv" + AlgorithmKey = "alg" + CompressionKey = "zip" + ContentEncryptionKey = "enc" + ContentTypeKey = "cty" + CriticalKey = "crit" + EphemeralPublicKeyKey = "epk" + JWKKey = "jwk" + JWKSetURLKey = "jku" + KeyIDKey = "kid" + TypeKey = "typ" + X509CertChainKey = "x5c" + X509CertThumbprintKey = "x5t" + X509CertThumbprintS256Key = "x5t#S256" + X509URLKey = "x5u" +) + +// Headers describe a standard JWE Header set. It is part of the JWE message +// and is used to represent both Protected and Unprotected headers, +// which in turn can be found in each Recipient object. +// If you are not sure how this works, it is strongly recommended that +// you read RFC7516, especially the section +// that describes the full JSON serialization format of JWE messages. +// +// In most cases, you likely want to use the protected headers, as this is the part of the encrypted content +type Headers interface { + AgreementPartyUInfo() ([]byte, bool) + AgreementPartyVInfo() ([]byte, bool) + Algorithm() (jwa.KeyEncryptionAlgorithm, bool) + Compression() (jwa.CompressionAlgorithm, bool) + ContentEncryption() (jwa.ContentEncryptionAlgorithm, bool) + ContentType() (string, bool) + Critical() ([]string, bool) + EphemeralPublicKey() (jwk.Key, bool) + JWK() (jwk.Key, bool) + JWKSetURL() (string, bool) + KeyID() (string, bool) + Type() (string, bool) + X509CertChain() (*cert.Chain, bool) + X509CertThumbprint() (string, bool) + X509CertThumbprintS256() (string, bool) + X509URL() (string, bool) + + // Get is used to extract the value of any field, including non-standard fields, out of the header. + // + // The first argument is the name of the field. The second argument is a pointer + // to a variable that will receive the value of the field. The method returns + // an error if the field does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + Get(string, any) error + Set(string, any) error + Remove(string) error + // Has returns true if the specified header has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + Encode() ([]byte, error) + Decode([]byte) error + Clone() (Headers, error) + Copy(Headers) error + Merge(Headers) (Headers, error) + + // Keys returns a list of the keys contained in this header. + Keys() []string +} + +// stdHeaderNames is a list of all standard header names defined in the JWE specification. +var stdHeaderNames = []string{AgreementPartyUInfoKey, AgreementPartyVInfoKey, AlgorithmKey, CompressionKey, ContentEncryptionKey, ContentTypeKey, CriticalKey, EphemeralPublicKeyKey, JWKKey, JWKSetURLKey, KeyIDKey, TypeKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, X509URLKey} + +type stdHeaders struct { + agreementPartyUInfo []byte + agreementPartyVInfo []byte + algorithm *jwa.KeyEncryptionAlgorithm + compression *jwa.CompressionAlgorithm + contentEncryption *jwa.ContentEncryptionAlgorithm + contentType *string + critical []string + ephemeralPublicKey jwk.Key + jwk jwk.Key + jwkSetURL *string + keyID *string + typ *string + x509CertChain *cert.Chain + x509CertThumbprint *string + x509CertThumbprintS256 *string + x509URL *string + privateParams map[string]any + mu *sync.RWMutex +} + +func NewHeaders() Headers { + return &stdHeaders{ + mu: &sync.RWMutex{}, + privateParams: map[string]any{}, + } +} + +func (h *stdHeaders) AgreementPartyUInfo() ([]byte, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.agreementPartyUInfo, h.agreementPartyUInfo != nil +} + +func (h *stdHeaders) AgreementPartyVInfo() ([]byte, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.agreementPartyVInfo, h.agreementPartyVInfo != nil +} + +func (h *stdHeaders) Algorithm() (jwa.KeyEncryptionAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.algorithm == nil { + return jwa.EmptyKeyEncryptionAlgorithm(), false + } + return *(h.algorithm), true +} + +func (h *stdHeaders) Compression() (jwa.CompressionAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.compression == nil { + return jwa.NoCompress(), false + } + return *(h.compression), true +} + +func (h *stdHeaders) ContentEncryption() (jwa.ContentEncryptionAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.contentEncryption == nil { + return jwa.EmptyContentEncryptionAlgorithm(), false + } + return *(h.contentEncryption), true +} + +func (h *stdHeaders) ContentType() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.contentType == nil { + return "", false + } + return *(h.contentType), true +} + +func (h *stdHeaders) Critical() ([]string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.critical, h.critical != nil +} + +func (h *stdHeaders) EphemeralPublicKey() (jwk.Key, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.ephemeralPublicKey, h.ephemeralPublicKey != nil +} + +func (h *stdHeaders) JWK() (jwk.Key, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.jwk, h.jwk != nil +} + +func (h *stdHeaders) JWKSetURL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.jwkSetURL == nil { + return "", false + } + return *(h.jwkSetURL), true +} + +func (h *stdHeaders) KeyID() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.keyID == nil { + return "", false + } + return *(h.keyID), true +} + +func (h *stdHeaders) Type() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.typ == nil { + return "", false + } + return *(h.typ), true +} + +func (h *stdHeaders) X509CertChain() (*cert.Chain, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.x509CertChain, h.x509CertChain != nil +} + +func (h *stdHeaders) X509CertThumbprint() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprint == nil { + return "", false + } + return *(h.x509CertThumbprint), true +} + +func (h *stdHeaders) X509CertThumbprintS256() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprintS256 == nil { + return "", false + } + return *(h.x509CertThumbprintS256), true +} + +func (h *stdHeaders) X509URL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509URL == nil { + return "", false + } + return *(h.x509URL), true +} + +func (h *stdHeaders) PrivateParams() map[string]any { + h.mu.RLock() + defer h.mu.RUnlock() + return h.privateParams +} + +func (h *stdHeaders) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AgreementPartyUInfoKey: + return h.agreementPartyUInfo != nil + case AgreementPartyVInfoKey: + return h.agreementPartyVInfo != nil + case AlgorithmKey: + return h.algorithm != nil + case CompressionKey: + return h.compression != nil + case ContentEncryptionKey: + return h.contentEncryption != nil + case ContentTypeKey: + return h.contentType != nil + case CriticalKey: + return h.critical != nil + case EphemeralPublicKeyKey: + return h.ephemeralPublicKey != nil + case JWKKey: + return h.jwk != nil + case JWKSetURLKey: + return h.jwkSetURL != nil + case KeyIDKey: + return h.keyID != nil + case TypeKey: + return h.typ != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *stdHeaders) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AgreementPartyUInfoKey: + if h.agreementPartyUInfo == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.agreementPartyUInfo); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case AgreementPartyVInfoKey: + if h.agreementPartyVInfo == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.agreementPartyVInfo); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case CompressionKey: + if h.compression == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.compression)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case ContentEncryptionKey: + if h.contentEncryption == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.contentEncryption)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case ContentTypeKey: + if h.contentType == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.contentType)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case CriticalKey: + if h.critical == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.critical); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case EphemeralPublicKeyKey: + if h.ephemeralPublicKey == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.ephemeralPublicKey); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case JWKKey: + if h.jwk == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.jwk); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case JWKSetURLKey: + if h.jwkSetURL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.jwkSetURL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case TypeKey: + if h.typ == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.typ)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *stdHeaders) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *stdHeaders) setNoLock(name string, value any) error { + switch name { + case AgreementPartyUInfoKey: + if v, ok := value.([]byte); ok { + h.agreementPartyUInfo = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, AgreementPartyUInfoKey, value) + case AgreementPartyVInfoKey: + if v, ok := value.([]byte); ok { + h.agreementPartyVInfo = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, AgreementPartyVInfoKey, value) + case AlgorithmKey: + if v, ok := value.(jwa.KeyEncryptionAlgorithm); ok { + h.algorithm = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, AlgorithmKey, value) + case CompressionKey: + if v, ok := value.(jwa.CompressionAlgorithm); ok { + h.compression = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, CompressionKey, value) + case ContentEncryptionKey: + if v, ok := value.(jwa.ContentEncryptionAlgorithm); ok { + if v == jwa.EmptyContentEncryptionAlgorithm() { + return fmt.Errorf(`"enc" field cannot be an empty string`) + } + h.contentEncryption = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ContentEncryptionKey, value) + case ContentTypeKey: + if v, ok := value.(string); ok { + h.contentType = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ContentTypeKey, value) + case CriticalKey: + if v, ok := value.([]string); ok { + h.critical = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, CriticalKey, value) + case EphemeralPublicKeyKey: + if v, ok := value.(jwk.Key); ok { + h.ephemeralPublicKey = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, EphemeralPublicKeyKey, value) + case JWKKey: + if v, ok := value.(jwk.Key); ok { + h.jwk = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKKey, value) + case JWKSetURLKey: + if v, ok := value.(string); ok { + h.jwkSetURL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKSetURLKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case TypeKey: + if v, ok := value.(string); ok { + h.typ = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, TypeKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (h *stdHeaders) Remove(key string) error { + h.mu.Lock() + defer h.mu.Unlock() + switch key { + case AgreementPartyUInfoKey: + h.agreementPartyUInfo = nil + case AgreementPartyVInfoKey: + h.agreementPartyVInfo = nil + case AlgorithmKey: + h.algorithm = nil + case CompressionKey: + h.compression = nil + case ContentEncryptionKey: + h.contentEncryption = nil + case ContentTypeKey: + h.contentType = nil + case CriticalKey: + h.critical = nil + case EphemeralPublicKeyKey: + h.ephemeralPublicKey = nil + case JWKKey: + h.jwk = nil + case JWKSetURLKey: + h.jwkSetURL = nil + case KeyIDKey: + h.keyID = nil + case TypeKey: + h.typ = nil + case X509CertChainKey: + h.x509CertChain = nil + case X509CertThumbprintKey: + h.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + h.x509CertThumbprintS256 = nil + case X509URLKey: + h.x509URL = nil + default: + delete(h.privateParams, key) + } + return nil +} + +func (h *stdHeaders) UnmarshalJSON(buf []byte) error { + h.agreementPartyUInfo = nil + h.agreementPartyVInfo = nil + h.algorithm = nil + h.compression = nil + h.contentEncryption = nil + h.contentType = nil + h.critical = nil + h.ephemeralPublicKey = nil + h.jwk = nil + h.jwkSetURL = nil + h.keyID = nil + h.typ = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case AgreementPartyUInfoKey: + if err := json.AssignNextBytesToken(&h.agreementPartyUInfo, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AgreementPartyUInfoKey, err) + } + case AgreementPartyVInfoKey: + if err := json.AssignNextBytesToken(&h.agreementPartyVInfo, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AgreementPartyVInfoKey, err) + } + case AlgorithmKey: + var decoded jwa.KeyEncryptionAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &decoded + case CompressionKey: + var decoded jwa.CompressionAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, CompressionKey, err) + } + h.compression = &decoded + case ContentEncryptionKey: + var decoded jwa.ContentEncryptionAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ContentEncryptionKey, err) + } + h.contentEncryption = &decoded + case ContentTypeKey: + if err := json.AssignNextStringToken(&h.contentType, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ContentTypeKey, err) + } + case CriticalKey: + var decoded []string + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, CriticalKey, err) + } + h.critical = decoded + case EphemeralPublicKeyKey: + var buf json.RawMessage + if err := dec.Decode(&buf); err != nil { + return fmt.Errorf(`failed to decode value for key %s:%w`, EphemeralPublicKeyKey, err) + } + key, err := jwk.ParseKey(buf) + if err != nil { + return fmt.Errorf(`failed to parse JWK for key %s: %w`, EphemeralPublicKeyKey, err) + } + h.ephemeralPublicKey = key + case JWKKey: + var buf json.RawMessage + if err := dec.Decode(&buf); err != nil { + return fmt.Errorf(`failed to decode value for key %s:%w`, JWKKey, err) + } + key, err := jwk.ParseKey(buf) + if err != nil { + return fmt.Errorf(`failed to parse JWK for key %s: %w`, JWKKey, err) + } + h.jwk = key + case JWKSetURLKey: + if err := json.AssignNextStringToken(&h.jwkSetURL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JWKSetURLKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case TypeKey: + if err := json.AssignNextStringToken(&h.typ, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, TypeKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + decoded, err := registry.Decode(dec, tok) + if err != nil { + return err + } + h.setNoLock(tok, decoded) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + return nil +} + +func (h *stdHeaders) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 16+len(h.privateParams)) + if h.agreementPartyUInfo != nil { + keys = append(keys, AgreementPartyUInfoKey) + } + if h.agreementPartyVInfo != nil { + keys = append(keys, AgreementPartyVInfoKey) + } + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.compression != nil { + keys = append(keys, CompressionKey) + } + if h.contentEncryption != nil { + keys = append(keys, ContentEncryptionKey) + } + if h.contentType != nil { + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + keys = append(keys, CriticalKey) + } + if h.ephemeralPublicKey != nil { + keys = append(keys, EphemeralPublicKeyKey) + } + if h.jwk != nil { + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +func (h stdHeaders) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + keys := make([]string, 0, 16+len(h.privateParams)) + h.mu.RLock() + if h.agreementPartyUInfo != nil { + data[AgreementPartyUInfoKey] = h.agreementPartyUInfo + keys = append(keys, AgreementPartyUInfoKey) + } + if h.agreementPartyVInfo != nil { + data[AgreementPartyVInfoKey] = h.agreementPartyVInfo + keys = append(keys, AgreementPartyVInfoKey) + } + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + keys = append(keys, AlgorithmKey) + } + if h.compression != nil { + data[CompressionKey] = *(h.compression) + keys = append(keys, CompressionKey) + } + if h.contentEncryption != nil { + data[ContentEncryptionKey] = *(h.contentEncryption) + keys = append(keys, ContentEncryptionKey) + } + if h.contentType != nil { + data[ContentTypeKey] = *(h.contentType) + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + data[CriticalKey] = h.critical + keys = append(keys, CriticalKey) + } + if h.ephemeralPublicKey != nil { + data[EphemeralPublicKeyKey] = h.ephemeralPublicKey + keys = append(keys, EphemeralPublicKeyKey) + } + if h.jwk != nil { + data[JWKKey] = h.jwk + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + data[JWKSetURLKey] = *(h.jwkSetURL) + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + data[TypeKey] = *(h.typ) + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + keys = append(keys, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + keys = append(keys, k) + } + h.mu.RUnlock() + + sort.Strings(keys) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + for i, k := range keys { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(k) + buf.WriteString(`":`) + v := data[k] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s`, k) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *stdHeaders) clear() { + h.mu.Lock() + h.agreementPartyUInfo = nil + h.agreementPartyVInfo = nil + h.algorithm = nil + h.compression = nil + h.contentEncryption = nil + h.contentType = nil + h.critical = nil + h.ephemeralPublicKey = nil + h.jwk = nil + h.jwkSetURL = nil + h.keyID = nil + h.typ = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.privateParams = map[string]any{} + h.mu.Unlock() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/interface.go new file mode 100644 index 0000000000..91ad8cb809 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/interface.go @@ -0,0 +1,207 @@ +package jwe + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// KeyEncrypter is an interface for object that can encrypt a +// content encryption key. +// +// You can use this in place of a regular key (i.e. in jwe.WithKey()) +// to encrypt the content encryption key in a JWE message without +// having to expose the secret key in memory, for example, when you +// want to use hardware security modules (HSMs) to encrypt the key. +// +// This API is experimental and may change without notice, even +// in minor releases. +type KeyEncrypter interface { + // Algorithm returns the algorithm used to encrypt the key. + Algorithm() jwa.KeyEncryptionAlgorithm + + // EncryptKey encrypts the given content encryption key. + EncryptKey([]byte) ([]byte, error) +} + +// KeyIDer is an interface for things that can return a key ID. +// +// As of this writing, this is solely used to identify KeyEncrypter +// objects that also carry a key ID on its own. +type KeyIDer interface { + KeyID() (string, bool) +} + +// KeyDecrypter is an interface for objects that can decrypt a content +// encryption key. +// +// You can use this in place of a regular key (i.e. in jwe.WithKey()) +// to decrypt the encrypted key in a JWE message without having to +// expose the secret key in memory, for example, when you want to use +// hardware security modules (HSMs) to decrypt the key. +// +// This API is experimental and may change without notice, even +// in minor releases. +type KeyDecrypter interface { + // Decrypt decrypts the encrypted key of a JWE message. + // + // Make sure you understand how JWE messages are structured. + // + // For example, while in most circumstances a JWE message will only have one recipient, + // a JWE message may contain multiple recipients, each with their own + // encrypted key. This method will be called for each recipient, instead of + // just once for a message. + // + // Also, header values could be found in either protected/unprotected headers + // of a JWE message, as well as in protected/unprotected headers for each recipient. + // When checking a header value, you can decide to use either one, or both, but you + // must be aware that there are multiple places to look for. + DecryptKey(alg jwa.KeyEncryptionAlgorithm, encryptedKey []byte, recipient Recipient, message *Message) ([]byte, error) +} + +// Recipient holds the encrypted key and hints to decrypt the key +type Recipient interface { + Headers() Headers + EncryptedKey() []byte + SetHeaders(Headers) error + SetEncryptedKey([]byte) error +} + +type stdRecipient struct { + // Comments on each field are taken from https://datatracker.ietf.org/doc/html/rfc7516 + // + // header + // The "header" member MUST be present and contain the value JWE Per- + // Recipient Unprotected Header when the JWE Per-Recipient + // Unprotected Header value is non-empty; otherwise, it MUST be + // absent. This value is represented as an unencoded JSON object, + // rather than as a string. These Header Parameter values are not + // integrity protected. + // + // At least one of the "header", "protected", and "unprotected" members + // MUST be present so that "alg" and "enc" Header Parameter values are + // conveyed for each recipient computation. + // + // JWX note: see Message.unprotectedHeaders + headers Headers + + // encrypted_key + // The "encrypted_key" member MUST be present and contain the value + // BASE64URL(JWE Encrypted Key) when the JWE Encrypted Key value is + // non-empty; otherwise, it MUST be absent. + encryptedKey []byte +} + +// Message contains the entire encrypted JWE message. You should not +// expect to use Message for anything other than inspecting the +// state of an encrypted message. This is because encryption is +// highly context-sensitive, and once we parse the original payload +// into an object, we may not always be able to recreate the exact +// context in which the encryption happened. +// +// For example, it is totally valid for if the protected header's +// integrity was calculated using a non-standard line breaks: +// +// {"a dummy": +// "protected header"} +// +// Once parsed, though, we can only serialize the protected header as: +// +// {"a dummy":"protected header"} +// +// which would obviously result in a contradicting integrity value +// if we tried to re-calculate it from a parsed message. +// +//nolint:govet +type Message struct { + // Comments on each field are taken from https://datatracker.ietf.org/doc/html/rfc7516 + // + // protected + // The "protected" member MUST be present and contain the value + // BASE64URL(UTF8(JWE Protected Header)) when the JWE Protected + // Header value is non-empty; otherwise, it MUST be absent. These + // Header Parameter values are integrity protected. + protectedHeaders Headers + + // unprotected + // The "unprotected" member MUST be present and contain the value JWE + // Shared Unprotected Header when the JWE Shared Unprotected Header + // value is non-empty; otherwise, it MUST be absent. This value is + // represented as an unencoded JSON object, rather than as a string. + // These Header Parameter values are not integrity protected. + // + // JWX note: This field is NOT mutually exclusive with per-recipient + // headers within the implementation because... it's too much work. + // It is _never_ populated (we don't provide a way to do this) upon encryption. + // When decrypting, if present its values are always merged with + // per-recipient header. + unprotectedHeaders Headers + + // iv + // The "iv" member MUST be present and contain the value + // BASE64URL(JWE Initialization Vector) when the JWE Initialization + // Vector value is non-empty; otherwise, it MUST be absent. + initializationVector []byte + + // aad + // The "aad" member MUST be present and contain the value + // BASE64URL(JWE AAD)) when the JWE AAD value is non-empty; + // otherwise, it MUST be absent. A JWE AAD value can be included to + // supply a base64url-encoded value to be integrity protected but not + // encrypted. + authenticatedData []byte + + // ciphertext + // The "ciphertext" member MUST be present and contain the value + // BASE64URL(JWE Ciphertext). + cipherText []byte + + // tag + // The "tag" member MUST be present and contain the value + // BASE64URL(JWE Authentication Tag) when the JWE Authentication Tag + // value is non-empty; otherwise, it MUST be absent. + tag []byte + + // recipients + // The "recipients" member value MUST be an array of JSON objects. + // Each object contains information specific to a single recipient. + // This member MUST be present with exactly one array element per + // recipient, even if some or all of the array element values are the + // empty JSON object "{}" (which can happen when all Header Parameter + // values are shared between all recipients and when no encrypted key + // is used, such as when doing Direct Encryption). + // + // Some Header Parameters, including the "alg" parameter, can be shared + // among all recipient computations. Header Parameters in the JWE + // Protected Header and JWE Shared Unprotected Header values are shared + // among all recipients. + // + // The Header Parameter values used when creating or validating per- + // recipient ciphertext and Authentication Tag values are the union of + // the three sets of Header Parameter values that may be present: (1) + // the JWE Protected Header represented in the "protected" member, (2) + // the JWE Shared Unprotected Header represented in the "unprotected" + // member, and (3) the JWE Per-Recipient Unprotected Header represented + // in the "header" member of the recipient's array element. The union + // of these sets of Header Parameters comprises the JOSE Header. The + // Header Parameter names in the three locations MUST be disjoint. + recipients []Recipient + + // TODO: Additional members can be present in both the JSON objects defined + // above; if not understood by implementations encountering them, they + // MUST be ignored. + // privateParams map[string]any + + // These two fields below are not available for the public consumers of this object. + // rawProtectedHeaders stores the original protected header buffer + rawProtectedHeaders []byte + // storeProtectedHeaders is a hint to be used in UnmarshalJSON(). + // When this flag is true, UnmarshalJSON() will populate the + // rawProtectedHeaders field + storeProtectedHeaders bool +} + +// populater is an interface for things that may modify the +// JWE header. e.g. ByteWithECPrivateKey +type populater interface { + Populate(keygen.Setter) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/BUILD.bazel new file mode 100644 index 0000000000..4ed4c53fa3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/BUILD.bazel @@ -0,0 +1,22 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "aescbc", + srcs = ["aescbc.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc", + visibility = ["//:__subpackages__"], + deps = ["//internal/pool"], +) + +go_test( + name = "aescbc_test", + srcs = ["aescbc_test.go"], + embed = [":aescbc"], + deps = ["@com_github_stretchr_testify//require"] +) + +alias( + name = "go_default_library", + actual = ":aescbc", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/aescbc.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/aescbc.go new file mode 100644 index 0000000000..b572674e2d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc/aescbc.go @@ -0,0 +1,270 @@ +package aescbc + +import ( + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "crypto/subtle" + "encoding/binary" + "errors" + "fmt" + "hash" + "sync/atomic" + + "github.com/lestrrat-go/jwx/v3/internal/pool" +) + +const ( + NonceSize = 16 +) + +const defaultBufSize int64 = 256 * 1024 * 1024 + +var maxBufSize atomic.Int64 + +func init() { + SetMaxBufferSize(defaultBufSize) +} + +func SetMaxBufferSize(siz int64) { + if siz <= 0 { + siz = defaultBufSize + } + maxBufSize.Store(siz) +} + +func pad(buf []byte, n int) []byte { + rem := n - len(buf)%n + if rem == 0 { + return buf + } + + bufsiz := len(buf) + rem + mbs := maxBufSize.Load() + if int64(bufsiz) > mbs { + panic(fmt.Errorf("failed to allocate buffer")) + } + newbuf := make([]byte, bufsiz) + copy(newbuf, buf) + + for i := len(buf); i < len(newbuf); i++ { + newbuf[i] = byte(rem) + } + return newbuf +} + +// ref. https://github.com/golang/go/blob/c3db64c0f45e8f2d75c5b59401e0fc925701b6f4/src/crypto/tls/conn.go#L279-L324 +// +// extractPadding returns, in constant time, the length of the padding to remove +// from the end of payload. It also returns a byte which is equal to 255 if the +// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2. +func extractPadding(payload []byte) (toRemove int, good byte) { + if len(payload) < 1 { + return 0, 0 + } + + paddingLen := payload[len(payload)-1] + t := uint(len(payload)) - uint(paddingLen) + // if len(payload) > paddingLen then the MSB of t is zero + good = byte(int32(^t) >> 31) + + // The maximum possible padding length plus the actual length field + toCheck := 256 + // The length of the padded data is public, so we can use an if here + if toCheck > len(payload) { + toCheck = len(payload) + } + + for i := 1; i <= toCheck; i++ { + t := uint(paddingLen) - uint(i) + // if i <= paddingLen then the MSB of t is zero + mask := byte(int32(^t) >> 31) + b := payload[len(payload)-i] + good &^= mask&paddingLen ^ mask&b + } + + // We AND together the bits of good and replicate the result across + // all the bits. + good &= good << 4 + good &= good << 2 + good &= good << 1 + good = uint8(int8(good) >> 7) + + // Zero the padding length on error. This ensures any unchecked bytes + // are included in the MAC. Otherwise, an attacker that could + // distinguish MAC failures from padding failures could mount an attack + // similar to POODLE in SSL 3.0: given a good ciphertext that uses a + // full block's worth of padding, replace the final block with another + // block. If the MAC check passed but the padding check failed, the + // last byte of that block decrypted to the block size. + // + // See also macAndPaddingGood logic below. + paddingLen &= good + + toRemove = int(paddingLen) + return +} + +type Hmac struct { + blockCipher cipher.Block + hash func() hash.Hash + keysize int + tagsize int + integrityKey []byte +} + +type BlockCipherFunc func([]byte) (cipher.Block, error) + +func New(key []byte, f BlockCipherFunc) (hmac *Hmac, err error) { + keysize := len(key) / 2 + ikey := key[:keysize] + ekey := key[keysize:] + + bc, ciphererr := f(ekey) + if ciphererr != nil { + err = fmt.Errorf(`failed to execute block cipher function: %w`, ciphererr) + return + } + + var hfunc func() hash.Hash + switch keysize { + case 16: + hfunc = sha256.New + case 24: + hfunc = sha512.New384 + case 32: + hfunc = sha512.New + default: + return nil, fmt.Errorf("unsupported key size %d", keysize) + } + + return &Hmac{ + blockCipher: bc, + hash: hfunc, + integrityKey: ikey, + keysize: keysize, + tagsize: keysize, // NonceSize, + // While investigating GH #207, I stumbled upon another problem where + // the computed tags don't match on decrypt. After poking through the + // code using a bunch of debug statements, I've finally found out that + // tagsize = keysize makes the whole thing work. + }, nil +} + +// NonceSize fulfills the crypto.AEAD interface +func (c Hmac) NonceSize() int { + return NonceSize +} + +// Overhead fulfills the crypto.AEAD interface +func (c Hmac) Overhead() int { + return c.blockCipher.BlockSize() + c.tagsize +} + +func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) ([]byte, error) { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], uint64(len(aad)*8)) + + h := hmac.New(c.hash, c.integrityKey) + + // compute the tag + // no need to check errors because Write never returns an error: https://pkg.go.dev/hash#Hash + // + // > Write (via the embedded io.Writer interface) adds more data to the running hash. + // > It never returns an error. + h.Write(aad) + h.Write(nonce) + h.Write(ciphertext) + h.Write(buf[:]) + s := h.Sum(nil) + return s[:c.tagsize], nil +} + +func ensureSize(dst []byte, n int) []byte { + // if the dst buffer has enough length just copy the relevant parts to it. + // Otherwise create a new slice that's big enough, and operate on that + // Note: I think go-jose has a bug in that it checks for cap(), but not len(). + ret := dst + if diff := n - len(dst); diff > 0 { + // dst is not big enough + ret = make([]byte, n) + copy(ret, dst) + } + return ret +} + +// Seal fulfills the crypto.AEAD interface +func (c Hmac) Seal(dst, nonce, plaintext, data []byte) []byte { + ctlen := len(plaintext) + bufsiz := ctlen + c.Overhead() + mbs := maxBufSize.Load() + + if int64(bufsiz) > mbs { + panic(fmt.Errorf("failed to allocate buffer")) + } + ciphertext := make([]byte, bufsiz)[:ctlen] + copy(ciphertext, plaintext) + ciphertext = pad(ciphertext, c.blockCipher.BlockSize()) + + cbc := cipher.NewCBCEncrypter(c.blockCipher, nonce) + cbc.CryptBlocks(ciphertext, ciphertext) + + authtag, err := c.ComputeAuthTag(data, nonce, ciphertext) + if err != nil { + // Hmac implements cipher.AEAD interface. Seal can't return error. + // But currently it never reach here because of Hmac.ComputeAuthTag doesn't return error. + panic(fmt.Errorf("failed to seal on hmac: %v", err)) + } + + retlen := len(dst) + len(ciphertext) + len(authtag) + + ret := ensureSize(dst, retlen) + out := ret[len(dst):] + n := copy(out, ciphertext) + copy(out[n:], authtag) + + return ret +} + +// Open fulfills the crypto.AEAD interface +func (c Hmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + if len(ciphertext) < c.keysize { + return nil, fmt.Errorf(`invalid ciphertext (too short)`) + } + + tagOffset := len(ciphertext) - c.tagsize + if tagOffset%c.blockCipher.BlockSize() != 0 { + return nil, fmt.Errorf( + "invalid ciphertext (invalid length: %d %% %d != 0)", + tagOffset, + c.blockCipher.BlockSize(), + ) + } + tag := ciphertext[tagOffset:] + ciphertext = ciphertext[:tagOffset] + + expectedTag, err := c.ComputeAuthTag(data, nonce, ciphertext[:tagOffset]) + if err != nil { + return nil, fmt.Errorf(`failed to compute auth tag: %w`, err) + } + + cbc := cipher.NewCBCDecrypter(c.blockCipher, nonce) + buf := pool.ByteSlice().GetCapacity(tagOffset) + defer pool.ByteSlice().Put(buf) + buf = buf[:tagOffset] + + cbc.CryptBlocks(buf, ciphertext) + + toRemove, good := extractPadding(buf) + cmp := subtle.ConstantTimeCompare(expectedTag, tag) & int(good) + if cmp != 1 { + return nil, errors.New(`invalid ciphertext`) + } + + plaintext := buf[:len(buf)-toRemove] + ret := ensureSize(dst, len(plaintext)) + out := ret[len(dst):] + copy(out, plaintext) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/BUILD.bazel new file mode 100644 index 0000000000..cf642c744d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/BUILD.bazel @@ -0,0 +1,34 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "cipher", + srcs = [ + "cipher.go", + "interface.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher", + visibility = ["//:__subpackages__"], + deps = [ + "//jwa", + "//jwe/internal/aescbc", + "//jwe/internal/keygen", + "//internal/tokens", + ], +) + +go_test( + name = "cipher_test", + srcs = ["cipher_test.go"], + deps = [ + ":cipher", + "//jwa", + "//internal/tokens", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":cipher", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/cipher.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/cipher.go new file mode 100644 index 0000000000..9b9a40d00d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/cipher.go @@ -0,0 +1,169 @@ +package cipher + +import ( + "crypto/aes" + "crypto/cipher" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +var gcm = &gcmFetcher{} +var cbc = &cbcFetcher{} + +func (f gcmFetcher) Fetch(key []byte, size int) (cipher.AEAD, error) { + if len(key) != size { + return nil, fmt.Errorf(`key size (%d) does not match expected key size (%d)`, len(key), size) + } + aescipher, err := aes.NewCipher(key) + if err != nil { + return nil, fmt.Errorf(`cipher: failed to create AES cipher for GCM: %w`, err) + } + + aead, err := cipher.NewGCM(aescipher) + if err != nil { + return nil, fmt.Errorf(`failed to create GCM for cipher: %w`, err) + } + return aead, nil +} + +func (f cbcFetcher) Fetch(key []byte, size int) (cipher.AEAD, error) { + if len(key) != size { + return nil, fmt.Errorf(`key size (%d) does not match expected key size (%d)`, len(key), size) + } + aead, err := aescbc.New(key, aes.NewCipher) + if err != nil { + return nil, fmt.Errorf(`cipher: failed to create AES cipher for CBC: %w`, err) + } + return aead, nil +} + +func (c AesContentCipher) KeySize() int { + return c.keysize +} + +func (c AesContentCipher) TagSize() int { + return c.tagsize +} + +func NewAES(alg string) (*AesContentCipher, error) { + var keysize int + var tagsize int + var fetcher Fetcher + switch alg { + case tokens.A128GCM: + keysize = 16 + tagsize = 16 + fetcher = gcm + case tokens.A192GCM: + keysize = 24 + tagsize = 16 + fetcher = gcm + case tokens.A256GCM: + keysize = 32 + tagsize = 16 + fetcher = gcm + case tokens.A128CBC_HS256: + tagsize = 16 + keysize = tagsize * 2 + fetcher = cbc + case tokens.A192CBC_HS384: + tagsize = 24 + keysize = tagsize * 2 + fetcher = cbc + case tokens.A256CBC_HS512: + tagsize = 32 + keysize = tagsize * 2 + fetcher = cbc + default: + return nil, fmt.Errorf("failed to create AES content cipher: invalid algorithm (%s)", alg) + } + + return &AesContentCipher{ + keysize: keysize, + tagsize: tagsize, + fetch: fetcher, + }, nil +} + +func (c AesContentCipher) Encrypt(cek, plaintext, aad []byte) (iv, ciphertxt, tag []byte, err error) { + var aead cipher.AEAD + aead, err = c.fetch.Fetch(cek, c.keysize) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to fetch AEAD: %w`, err) + } + + // Seal may panic (argh!), so protect ourselves from that + defer func() { + if e := recover(); e != nil { + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf("%s", e) + } + err = fmt.Errorf(`failed to encrypt: %w`, err) + } + }() + + if c.NonceGenerator != nil { + iv, err = c.NonceGenerator(aead.NonceSize()) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to generate nonce: %w`, err) + } + } else { + bs, err := keygen.Random(aead.NonceSize()) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to generate random nonce: %w`, err) + } + iv = bs.Bytes() + } + + combined := aead.Seal(nil, iv, plaintext, aad) + tagoffset := len(combined) - c.TagSize() + + if tagoffset < 0 { + panic(fmt.Sprintf("tag offset is less than 0 (combined len = %d, tagsize = %d)", len(combined), c.TagSize())) + } + + tag = combined[tagoffset:] + ciphertxt = make([]byte, tagoffset) + copy(ciphertxt, combined[:tagoffset]) + + return +} + +func (c AesContentCipher) Decrypt(cek, iv, ciphertxt, tag, aad []byte) (plaintext []byte, err error) { + aead, err := c.fetch.Fetch(cek, c.keysize) + if err != nil { + return nil, fmt.Errorf(`failed to fetch AEAD data: %w`, err) + } + + // Open may panic (argh!), so protect ourselves from that + defer func() { + if e := recover(); e != nil { + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf(`%s`, e) + } + err = fmt.Errorf(`failed to decrypt: %w`, err) + return + } + }() + + combined := make([]byte, len(ciphertxt)+len(tag)) + copy(combined, ciphertxt) + copy(combined[len(ciphertxt):], tag) + + buf, aeaderr := aead.Open(nil, iv, combined, aad) + if aeaderr != nil { + err = fmt.Errorf(`aead.Open failed: %w`, aeaderr) + return + } + plaintext = buf + return +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/interface.go new file mode 100644 index 0000000000..a03e15b159 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/cipher/interface.go @@ -0,0 +1,32 @@ +package cipher + +import ( + "crypto/cipher" +) + +const ( + TagSize = 16 +) + +// ContentCipher knows how to encrypt/decrypt the content given a content +// encryption key and other data +type ContentCipher interface { + KeySize() int + Encrypt(cek, aad, plaintext []byte) ([]byte, []byte, []byte, error) + Decrypt(cek, iv, aad, ciphertext, tag []byte) ([]byte, error) +} + +type Fetcher interface { + Fetch([]byte, int) (cipher.AEAD, error) +} + +type gcmFetcher struct{} +type cbcFetcher struct{} + +// AesContentCipher represents a cipher based on AES +type AesContentCipher struct { + NonceGenerator func(int) ([]byte, error) + fetch Fetcher + keysize int + tagsize int +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/BUILD.bazel new file mode 100644 index 0000000000..59aeb2cd27 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/BUILD.bazel @@ -0,0 +1,24 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "concatkdf", + srcs = ["concatkdf.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf", + visibility = ["//:__subpackages__"], +) + +go_test( + name = "concatkdf_test", + srcs = ["concatkdf_test.go"], + embed = [":concatkdf"], + deps = [ + "//jwa", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":concatkdf", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/concatkdf.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/concatkdf.go new file mode 100644 index 0000000000..3691830a63 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf/concatkdf.go @@ -0,0 +1,66 @@ +package concatkdf + +import ( + "crypto" + "encoding/binary" + "fmt" +) + +type KDF struct { + buf []byte + otherinfo []byte + z []byte + hash crypto.Hash +} + +func ndata(src []byte) []byte { + buf := make([]byte, 4+len(src)) + binary.BigEndian.PutUint32(buf, uint32(len(src))) + copy(buf[4:], src) + return buf +} + +func New(hash crypto.Hash, alg, Z, apu, apv, pubinfo, privinfo []byte) *KDF { + algbuf := ndata(alg) + apubuf := ndata(apu) + apvbuf := ndata(apv) + + concat := make([]byte, len(algbuf)+len(apubuf)+len(apvbuf)+len(pubinfo)+len(privinfo)) + n := copy(concat, algbuf) + n += copy(concat[n:], apubuf) + n += copy(concat[n:], apvbuf) + n += copy(concat[n:], pubinfo) + copy(concat[n:], privinfo) + + return &KDF{ + hash: hash, + otherinfo: concat, + z: Z, + } +} + +func (k *KDF) Read(out []byte) (int, error) { + var round uint32 = 1 + h := k.hash.New() + + for len(out) > len(k.buf) { + h.Reset() + + if err := binary.Write(h, binary.BigEndian, round); err != nil { + return 0, fmt.Errorf(`failed to write round using kdf: %w`, err) + } + if _, err := h.Write(k.z); err != nil { + return 0, fmt.Errorf(`failed to write z using kdf: %w`, err) + } + if _, err := h.Write(k.otherinfo); err != nil { + return 0, fmt.Errorf(`failed to write other info using kdf: %w`, err) + } + + k.buf = append(k.buf, h.Sum(nil)...) + round++ + } + + n := copy(out, k.buf[:len(out)]) + k.buf = k.buf[len(out):] + return n, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/BUILD.bazel new file mode 100644 index 0000000000..bb395200f8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "content_crypt", + srcs = [ + "content_crypt.go", + "interface.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt", + visibility = ["//:__subpackages__"], + deps = [ + "//jwa", + "//jwe/internal/cipher", + ], +) + +alias( + name = "go_default_library", + actual = ":content_crypt", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/content_crypt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/content_crypt.go new file mode 100644 index 0000000000..0ef45ed953 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/content_crypt.go @@ -0,0 +1,43 @@ +package content_crypt //nolint:golint + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher" +) + +func (c Generic) Algorithm() jwa.ContentEncryptionAlgorithm { + return c.alg +} + +func (c Generic) Encrypt(cek, plaintext, aad []byte) ([]byte, []byte, []byte, error) { + iv, encrypted, tag, err := c.cipher.Encrypt(cek, plaintext, aad) + if err != nil { + return nil, nil, nil, fmt.Errorf(`failed to crypt content: %w`, err) + } + + return iv, encrypted, tag, nil +} + +func (c Generic) Decrypt(cek, iv, ciphertext, tag, aad []byte) ([]byte, error) { + return c.cipher.Decrypt(cek, iv, ciphertext, tag, aad) +} + +func NewGeneric(alg jwa.ContentEncryptionAlgorithm) (*Generic, error) { + c, err := cipher.NewAES(alg.String()) + if err != nil { + return nil, fmt.Errorf(`aes crypt: failed to create content cipher: %w`, err) + } + + return &Generic{ + alg: alg, + cipher: c, + keysize: c.KeySize(), + tagsize: 16, + }, nil +} + +func (c Generic) KeySize() int { + return c.keysize +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/interface.go new file mode 100644 index 0000000000..84b42fe07d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt/interface.go @@ -0,0 +1,20 @@ +package content_crypt //nolint:golint + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher" +) + +// Generic encrypts a message by applying all the necessary +// modifications to the keys and the contents +type Generic struct { + alg jwa.ContentEncryptionAlgorithm + keysize int + tagsize int + cipher cipher.ContentCipher +} + +type Cipher interface { + Decrypt([]byte, []byte, []byte, []byte, []byte) ([]byte, error) + KeySize() int +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/BUILD.bazel new file mode 100644 index 0000000000..bde8eb68f7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/BUILD.bazel @@ -0,0 +1,24 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "keygen", + srcs = [ + "interface.go", + "keygen.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen", + visibility = ["//:__subpackages__"], + deps = [ + "//internal/ecutil", + "//jwa", + "//jwe/internal/concatkdf", + "//internal/tokens", + "//jwk", + ], +) + +alias( + name = "go_default_library", + actual = ":keygen", + visibility = ["//jwe:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/interface.go new file mode 100644 index 0000000000..7f8fb961a2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/interface.go @@ -0,0 +1,40 @@ +package keygen + +// ByteKey is a generated key that only has the key's byte buffer +// as its instance data. If a key needs to do more, such as providing +// values to be set in a JWE header, that key type wraps a ByteKey +type ByteKey []byte + +// ByteWithECPublicKey holds the EC private key that generated +// the key along with the key itself. This is required to set the +// proper values in the JWE headers +type ByteWithECPublicKey struct { + ByteKey + + PublicKey any +} + +type ByteWithIVAndTag struct { + ByteKey + + IV []byte + Tag []byte +} + +type ByteWithSaltAndCount struct { + ByteKey + + Salt []byte + Count int +} + +// ByteSource is an interface for things that return a byte sequence. +// This is used for KeyGenerator so that the result of computations can +// carry more than just the generate byte sequence. +type ByteSource interface { + Bytes() []byte +} + +type Setter interface { + Set(string, any) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/keygen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/keygen.go new file mode 100644 index 0000000000..daa7599d9f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/internal/keygen/keygen.go @@ -0,0 +1,139 @@ +package keygen + +import ( + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rand" + "encoding/binary" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// Bytes returns the byte from this ByteKey +func (k ByteKey) Bytes() []byte { + return []byte(k) +} + +func Random(n int) (ByteSource, error) { + buf := make([]byte, n) + if _, err := io.ReadFull(rand.Reader, buf); err != nil { + return nil, fmt.Errorf(`failed to read from rand.Reader: %w`, err) + } + return ByteKey(buf), nil +} + +// Ecdhes generates a new key using ECDH-ES +func Ecdhes(alg string, enc string, keysize int, pubkey *ecdsa.PublicKey, apu, apv []byte) (ByteSource, error) { + priv, err := ecdsa.GenerateKey(pubkey.Curve, rand.Reader) + if err != nil { + return nil, fmt.Errorf(`failed to generate key for ECDH-ES: %w`, err) + } + + var algorithm string + if alg == tokens.ECDH_ES { + algorithm = enc + } else { + algorithm = alg + } + + pubinfo := make([]byte, 4) + binary.BigEndian.PutUint32(pubinfo, uint32(keysize)*8) + + if !priv.PublicKey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { + return nil, fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`) + } + z, _ := priv.PublicKey.Curve.ScalarMult(pubkey.X, pubkey.Y, priv.D.Bytes()) + zBytes := ecutil.AllocECPointBuffer(z, priv.PublicKey.Curve) + defer ecutil.ReleaseECPointBuffer(zBytes) + kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, apu, apv, pubinfo, []byte{}) + kek := make([]byte, keysize) + if _, err := kdf.Read(kek); err != nil { + return nil, fmt.Errorf(`failed to read kdf: %w`, err) + } + + return ByteWithECPublicKey{ + PublicKey: &priv.PublicKey, + ByteKey: ByteKey(kek), + }, nil +} + +// X25519 generates a new key using ECDH-ES with X25519 +func X25519(alg string, enc string, keysize int, pubkey *ecdh.PublicKey) (ByteSource, error) { + priv, err := ecdh.X25519().GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf(`failed to generate key for X25519: %w`, err) + } + + var algorithm string + if alg == tokens.ECDH_ES { + algorithm = enc + } else { + algorithm = alg + } + + pubinfo := make([]byte, 4) + binary.BigEndian.PutUint32(pubinfo, uint32(keysize)*8) + + zBytes, err := priv.ECDH(pubkey) + if err != nil { + return nil, fmt.Errorf(`failed to compute Z: %w`, err) + } + kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, []byte{}, []byte{}, pubinfo, []byte{}) + kek := make([]byte, keysize) + if _, err := kdf.Read(kek); err != nil { + return nil, fmt.Errorf(`failed to read kdf: %w`, err) + } + + return ByteWithECPublicKey{ + PublicKey: priv.PublicKey(), + ByteKey: ByteKey(kek), + }, nil +} + +// HeaderPopulate populates the header with the required EC-DSA public key +// information ('epk' key) +func (k ByteWithECPublicKey) Populate(h Setter) error { + key, err := jwk.Import(k.PublicKey) + if err != nil { + return fmt.Errorf(`failed to create JWK: %w`, err) + } + + if err := h.Set("epk", key); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + return nil +} + +// HeaderPopulate populates the header with the required AES GCM +// parameters ('iv' and 'tag') +func (k ByteWithIVAndTag) Populate(h Setter) error { + if err := h.Set("iv", k.IV); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + if err := h.Set("tag", k.Tag); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + return nil +} + +// HeaderPopulate populates the header with the required PBES2 +// parameters ('p2s' and 'p2c') +func (k ByteWithSaltAndCount) Populate(h Setter) error { + if err := h.Set("p2c", k.Count); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + if err := h.Set("p2s", k.Salt); err != nil { + return fmt.Errorf(`failed to write header: %w`, err) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/io.go new file mode 100644 index 0000000000..a5d6aca8a3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/io.go @@ -0,0 +1,36 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jwe + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (*Message, error) { + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwe.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwe.go new file mode 100644 index 0000000000..5728021ec7 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwe.go @@ -0,0 +1,1036 @@ +//go:generate ../tools/cmd/genjwe.sh + +// Package jwe implements JWE as described in https://tools.ietf.org/html/rfc7516 +package jwe + +// #region imports +import ( + "bytes" + "context" + "crypto/ecdsa" + "errors" + "fmt" + "io" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwk" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// #region globals + +var muSettings sync.RWMutex +var maxPBES2Count = 10000 +var maxDecompressBufferSize int64 = 10 * 1024 * 1024 // 10MB + +func Settings(options ...GlobalOption) { + muSettings.Lock() + defer muSettings.Unlock() + for _, option := range options { + switch option.Ident() { + case identMaxPBES2Count{}: + if err := option.Value(&maxPBES2Count); err != nil { + panic(fmt.Sprintf("jwe.Settings: value for option WithMaxPBES2Count must be an int: %s", err)) + } + case identMaxDecompressBufferSize{}: + if err := option.Value(&maxDecompressBufferSize); err != nil { + panic(fmt.Sprintf("jwe.Settings: value for option WithMaxDecompressBufferSize must be an int64: %s", err)) + } + case identCBCBufferSize{}: + var v int64 + if err := option.Value(&v); err != nil { + panic(fmt.Sprintf("jwe.Settings: value for option WithCBCBufferSize must be an int64: %s", err)) + } + aescbc.SetMaxBufferSize(v) + } + } +} + +const ( + fmtInvalid = iota + fmtCompact + fmtJSON + fmtJSONPretty + fmtMax +) + +var _ = fmtInvalid +var _ = fmtMax + +var registry = json.NewRegistry() + +type recipientBuilder struct { + alg jwa.KeyEncryptionAlgorithm + key any + headers Headers +} + +func (b *recipientBuilder) Build(r Recipient, cek []byte, calg jwa.ContentEncryptionAlgorithm, _ *content_crypt.Generic) ([]byte, error) { + // we need the raw key for later use + rawKey := b.key + + var keyID string + if ke, ok := b.key.(KeyEncrypter); ok { + if kider, ok := ke.(KeyIDer); ok { + if v, ok := kider.KeyID(); ok { + keyID = v + } + } + } else if jwkKey, ok := b.key.(jwk.Key); ok { + // Meanwhile, grab the kid as well + if v, ok := jwkKey.KeyID(); ok { + keyID = v + } + + var raw any + if err := jwk.Export(jwkKey, &raw); err != nil { + return nil, fmt.Errorf(`jwe.Encrypt: recipientBuilder: failed to retrieve raw key out of %T: %w`, b.key, err) + } + + rawKey = raw + } + + // Extract ECDH-ES specific parameters if needed + var apu, apv []byte + if b.headers != nil { + if val, ok := b.headers.AgreementPartyUInfo(); ok { + apu = val + } + if val, ok := b.headers.AgreementPartyVInfo(); ok { + apv = val + } + } + + // Create the encrypter using the new jwebb pattern + enc, err := newEncrypter(b.alg, calg, b.key, rawKey, apu, apv) + if err != nil { + return nil, fmt.Errorf(`jwe.Encrypt: recipientBuilder: failed to create encrypter: %w`, err) + } + + if hdrs := b.headers; hdrs != nil { + _ = r.SetHeaders(hdrs) + } + + if err := r.Headers().Set(AlgorithmKey, b.alg); err != nil { + return nil, fmt.Errorf(`failed to set header: %w`, err) + } + + if keyID != "" { + if err := r.Headers().Set(KeyIDKey, keyID); err != nil { + return nil, fmt.Errorf(`failed to set header: %w`, err) + } + } + + var rawCEK []byte + enckey, err := enc.EncryptKey(cek) + if err != nil { + return nil, fmt.Errorf(`failed to encrypt key: %w`, err) + } + if b.alg == jwa.ECDH_ES() || b.alg == jwa.DIRECT() { + rawCEK = enckey.Bytes() + } else { + if err := r.SetEncryptedKey(enckey.Bytes()); err != nil { + return nil, fmt.Errorf(`failed to set encrypted key: %w`, err) + } + } + + if hp, ok := enckey.(populater); ok { + if err := hp.Populate(r.Headers()); err != nil { + return nil, fmt.Errorf(`failed to populate: %w`, err) + } + } + + return rawCEK, nil +} + +// Encrypt generates a JWE message for the given payload and returns +// it in serialized form, which can be in either compact or +// JSON format. Default is compact. +// +// You must pass at least one key to `jwe.Encrypt()` by using `jwe.WithKey()` +// option. +// +// jwe.Encrypt(payload, jwe.WithKey(alg, key)) +// jwe.Encrypt(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) +// +// Note that in the second example the `jws.WithJSON()` option is +// specified as well. This is because the compact serialization +// format does not support multiple recipients, and users must +// specifically ask for the JSON serialization format. +// +// Read the documentation for `jwe.WithKey()` to learn more about the +// possible values that can be used for `alg` and `key`. +// +// Look for options that return `jwe.EncryptOption` or `jws.EncryptDecryptOption` +// for a complete list of options that can be passed to this function. +func Encrypt(payload []byte, options ...EncryptOption) ([]byte, error) { + ec := encryptContextPool.Get() + defer encryptContextPool.Put(ec) + if err := ec.ProcessOptions(options); err != nil { + return nil, encryptError{fmt.Errorf(`jwe.Encrypt: failed to process options: %w`, err)} + } + ret, err := ec.EncryptMessage(payload, nil) + if err != nil { + return nil, encryptError{fmt.Errorf(`jwe.Encrypt: %w`, err)} + } + return ret, nil +} + +// EncryptStatic is exactly like Encrypt, except it accepts a static +// content encryption key (CEK). It is separated out from the main +// Encrypt function such that the latter does not accidentally use a static +// CEK. +// +// DO NOT attempt to use this function unless you completely understand the +// security implications to using static CEKs. You have been warned. +// +// This function is currently considered EXPERIMENTAL, and is subject to +// future changes across minor/micro versions. +func EncryptStatic(payload, cek []byte, options ...EncryptOption) ([]byte, error) { + if len(cek) <= 0 { + return nil, encryptError{fmt.Errorf(`jwe.EncryptStatic: empty CEK`)} + } + ec := encryptContextPool.Get() + defer encryptContextPool.Put(ec) + if err := ec.ProcessOptions(options); err != nil { + return nil, encryptError{fmt.Errorf(`jwe.EncryptStatic: failed to process options: %w`, err)} + } + ret, err := ec.EncryptMessage(payload, cek) + if err != nil { + return nil, encryptError{fmt.Errorf(`jwe.EncryptStatic: %w`, err)} + } + return ret, nil +} + +// decryptContext holds the state during JWE decryption, similar to JWS verifyContext +type decryptContext struct { + keyProviders []KeyProvider + keyUsed any + cek *[]byte + dst *Message + maxDecompressBufferSize int64 + //nolint:containedctx + ctx context.Context +} + +var decryptContextPool = pool.New(allocDecryptContext, freeDecryptContext) + +func allocDecryptContext() *decryptContext { + return &decryptContext{ + ctx: context.Background(), + } +} + +func freeDecryptContext(dc *decryptContext) *decryptContext { + dc.keyProviders = dc.keyProviders[:0] + dc.keyUsed = nil + dc.cek = nil + dc.dst = nil + dc.maxDecompressBufferSize = 0 + dc.ctx = context.Background() + return dc +} + +func (dc *decryptContext) ProcessOptions(options []DecryptOption) error { + // Set default max decompress buffer size + muSettings.RLock() + dc.maxDecompressBufferSize = maxDecompressBufferSize + muSettings.RUnlock() + + for _, option := range options { + switch option.Ident() { + case identMessage{}: + if err := option.Value(&dc.dst); err != nil { + return fmt.Errorf("jwe.decrypt: WithMessage must be a *jwe.Message: %w", err) + } + case identKeyProvider{}: + var kp KeyProvider + if err := option.Value(&kp); err != nil { + return fmt.Errorf("jwe.decrypt: WithKeyProvider must be a KeyProvider: %w", err) + } + dc.keyProviders = append(dc.keyProviders, kp) + case identKeyUsed{}: + if err := option.Value(&dc.keyUsed); err != nil { + return fmt.Errorf("jwe.decrypt: WithKeyUsed must be an any: %w", err) + } + case identKey{}: + var pair *withKey + if err := option.Value(&pair); err != nil { + return fmt.Errorf("jwe.decrypt: WithKey must be a *withKey: %w", err) + } + alg, ok := pair.alg.(jwa.KeyEncryptionAlgorithm) + if !ok { + return fmt.Errorf("jwe.decrypt: WithKey() option must be specified using jwa.KeyEncryptionAlgorithm (got %T)", pair.alg) + } + dc.keyProviders = append(dc.keyProviders, &staticKeyProvider{alg: alg, key: pair.key}) + case identCEK{}: + if err := option.Value(&dc.cek); err != nil { + return fmt.Errorf("jwe.decrypt: WithCEK must be a *[]byte: %w", err) + } + case identMaxDecompressBufferSize{}: + if err := option.Value(&dc.maxDecompressBufferSize); err != nil { + return fmt.Errorf("jwe.decrypt: WithMaxDecompressBufferSize must be int64: %w", err) + } + case identContext{}: + if err := option.Value(&dc.ctx); err != nil { + return fmt.Errorf("jwe.decrypt: WithContext must be a context.Context: %w", err) + } + } + } + + if len(dc.keyProviders) < 1 { + return fmt.Errorf(`jwe.Decrypt: no key providers have been provided (see jwe.WithKey(), jwe.WithKeySet(), and jwe.WithKeyProvider()`) + } + + return nil +} + +func (dc *decryptContext) DecryptMessage(buf []byte) ([]byte, error) { + msg, err := parseJSONOrCompact(buf, true) + if err != nil { + return nil, fmt.Errorf(`failed to parse buffer for Decrypt: %w`, err) + } + + // Process things that are common to the message + h, err := msg.protectedHeaders.Clone() + if err != nil { + return nil, fmt.Errorf(`failed to copy protected headers: %w`, err) + } + h, err = h.Merge(msg.unprotectedHeaders) + if err != nil { + return nil, fmt.Errorf(`failed to merge headers for message decryption: %w`, err) + } + + var aad []byte + if aadContainer := msg.authenticatedData; aadContainer != nil { + aad = base64.Encode(aadContainer) + } + + var computedAad []byte + if len(msg.rawProtectedHeaders) > 0 { + computedAad = msg.rawProtectedHeaders + } else { + // this is probably not required once msg.Decrypt is deprecated + var err error + computedAad, err = msg.protectedHeaders.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to encode protected headers: %w`, err) + } + } + + // for each recipient, attempt to match the key providers + // if we have no recipients, pretend like we only have one + recipients := msg.recipients + if len(recipients) == 0 { + r := NewRecipient() + if err := r.SetHeaders(msg.protectedHeaders); err != nil { + return nil, fmt.Errorf(`failed to set headers to recipient: %w`, err) + } + recipients = append(recipients, r) + } + + errs := make([]error, 0, len(recipients)) + for _, recipient := range recipients { + decrypted, err := dc.tryRecipient(msg, recipient, h, aad, computedAad) + if err != nil { + errs = append(errs, recipientError{err}) + continue + } + if dc.dst != nil { + *dc.dst = *msg + dc.dst.rawProtectedHeaders = nil + dc.dst.storeProtectedHeaders = false + } + return decrypted, nil + } + return nil, fmt.Errorf(`failed to decrypt any of the recipients: %w`, errors.Join(errs...)) +} + +func (dc *decryptContext) tryRecipient(msg *Message, recipient Recipient, protectedHeaders Headers, aad, computedAad []byte) ([]byte, error) { + var tried int + var lastError error + for i, kp := range dc.keyProviders { + var sink algKeySink + if err := kp.FetchKeys(dc.ctx, &sink, recipient, msg); err != nil { + return nil, fmt.Errorf(`key provider %d failed: %w`, i, err) + } + + for _, pair := range sink.list { + tried++ + // alg is converted here because pair.alg is of type jwa.KeyAlgorithm. + // this may seem ugly, but we're trying to avoid declaring separate + // structs for `alg jwa.KeyEncryptionAlgorithm` and `alg jwa.SignatureAlgorithm` + //nolint:forcetypeassert + alg := pair.alg.(jwa.KeyEncryptionAlgorithm) + key := pair.key + + decrypted, err := dc.decryptContent(msg, alg, key, recipient, protectedHeaders, aad, computedAad) + if err != nil { + lastError = err + continue + } + + if dc.keyUsed != nil { + if err := blackmagic.AssignIfCompatible(dc.keyUsed, key); err != nil { + return nil, fmt.Errorf(`failed to assign used key (%T) to %T: %w`, key, dc.keyUsed, err) + } + } + return decrypted, nil + } + } + return nil, fmt.Errorf(`jwe.Decrypt: tried %d keys, but failed to match any of the keys with recipient (last error = %s)`, tried, lastError) +} + +func (dc *decryptContext) decryptContent(msg *Message, alg jwa.KeyEncryptionAlgorithm, key any, recipient Recipient, protectedHeaders Headers, aad, computedAad []byte) ([]byte, error) { + if jwkKey, ok := key.(jwk.Key); ok { + var raw any + if err := jwk.Export(jwkKey, &raw); err != nil { + return nil, fmt.Errorf(`failed to retrieve raw key from %T: %w`, key, err) + } + key = raw + } + + ce, ok := msg.protectedHeaders.ContentEncryption() + if !ok { + return nil, fmt.Errorf(`jwe.Decrypt: failed to retrieve content encryption algorithm from protected headers`) + } + dec := newDecrypter(alg, ce, key). + AuthenticatedData(aad). + ComputedAuthenticatedData(computedAad). + InitializationVector(msg.initializationVector). + Tag(msg.tag). + CEK(dc.cek) + + if v, ok := recipient.Headers().Algorithm(); !ok || v != alg { + // algorithms don't match + return nil, fmt.Errorf(`jwe.Decrypt: key (%q) and recipient (%q) algorithms do not match`, alg, v) + } + + h2, err := protectedHeaders.Clone() + if err != nil { + return nil, fmt.Errorf(`jwe.Decrypt: failed to copy headers (1): %w`, err) + } + + h2, err = h2.Merge(recipient.Headers()) + if err != nil { + return nil, fmt.Errorf(`failed to copy headers (2): %w`, err) + } + + switch alg { + case jwa.ECDH_ES(), jwa.ECDH_ES_A128KW(), jwa.ECDH_ES_A192KW(), jwa.ECDH_ES_A256KW(): + var epk any + if err := h2.Get(EphemeralPublicKeyKey, &epk); err != nil { + return nil, fmt.Errorf(`failed to get 'epk' field: %w`, err) + } + switch epk := epk.(type) { + case jwk.ECDSAPublicKey: + var pubkey ecdsa.PublicKey + if err := jwk.Export(epk, &pubkey); err != nil { + return nil, fmt.Errorf(`failed to get public key: %w`, err) + } + dec.PublicKey(&pubkey) + case jwk.OKPPublicKey: + var pubkey any + if err := jwk.Export(epk, &pubkey); err != nil { + return nil, fmt.Errorf(`failed to get public key: %w`, err) + } + dec.PublicKey(pubkey) + default: + return nil, fmt.Errorf("unexpected 'epk' type %T for alg %s", epk, alg) + } + + if apu, ok := h2.AgreementPartyUInfo(); ok && len(apu) > 0 { + dec.AgreementPartyUInfo(apu) + } + if apv, ok := h2.AgreementPartyVInfo(); ok && len(apv) > 0 { + dec.AgreementPartyVInfo(apv) + } + case jwa.A128GCMKW(), jwa.A192GCMKW(), jwa.A256GCMKW(): + var ivB64 string + if err := h2.Get(InitializationVectorKey, &ivB64); err == nil { + iv, err := base64.DecodeString(ivB64) + if err != nil { + return nil, fmt.Errorf(`failed to b64-decode 'iv': %w`, err) + } + dec.KeyInitializationVector(iv) + } + var tagB64 string + if err := h2.Get(TagKey, &tagB64); err == nil { + tag, err := base64.DecodeString(tagB64) + if err != nil { + return nil, fmt.Errorf(`failed to b64-decode 'tag': %w`, err) + } + dec.KeyTag(tag) + } + case jwa.PBES2_HS256_A128KW(), jwa.PBES2_HS384_A192KW(), jwa.PBES2_HS512_A256KW(): + var saltB64 string + if err := h2.Get(SaltKey, &saltB64); err != nil { + return nil, fmt.Errorf(`failed to get %q field`, SaltKey) + } + + // check if WithUseNumber is effective, because it will change the + // type of the underlying value (#1140) + var countFlt float64 + if json.UseNumber() { + var count json.Number + if err := h2.Get(CountKey, &count); err != nil { + return nil, fmt.Errorf(`failed to get %q field`, CountKey) + } + v, err := count.Float64() + if err != nil { + return nil, fmt.Errorf("failed to convert 'p2c' to float64: %w", err) + } + countFlt = v + } else { + var count float64 + if err := h2.Get(CountKey, &count); err != nil { + return nil, fmt.Errorf(`failed to get %q field`, CountKey) + } + countFlt = count + } + + muSettings.RLock() + maxCount := maxPBES2Count + muSettings.RUnlock() + if countFlt > float64(maxCount) { + return nil, fmt.Errorf("invalid 'p2c' value") + } + salt, err := base64.DecodeString(saltB64) + if err != nil { + return nil, fmt.Errorf(`failed to b64-decode 'salt': %w`, err) + } + dec.KeySalt(salt) + dec.KeyCount(int(countFlt)) + } + + plaintext, err := dec.Decrypt(recipient, msg.cipherText, msg) + if err != nil { + return nil, fmt.Errorf(`jwe.Decrypt: decryption failed: %w`, err) + } + + if v, ok := h2.Compression(); ok && v == jwa.Deflate() { + buf, err := uncompress(plaintext, dc.maxDecompressBufferSize) + if err != nil { + return nil, fmt.Errorf(`jwe.Derypt: failed to uncompress payload: %w`, err) + } + plaintext = buf + } + + if plaintext == nil { + return nil, fmt.Errorf(`failed to find matching recipient`) + } + + return plaintext, nil +} + +// encryptContext holds the state during JWE encryption, similar to JWS signContext +type encryptContext struct { + calg jwa.ContentEncryptionAlgorithm + compression jwa.CompressionAlgorithm + format int + builders []*recipientBuilder + protected Headers +} + +var encryptContextPool = pool.New(allocEncryptContext, freeEncryptContext) + +func allocEncryptContext() *encryptContext { + return &encryptContext{ + calg: jwa.A256GCM(), + compression: jwa.NoCompress(), + format: fmtCompact, + } +} + +func freeEncryptContext(ec *encryptContext) *encryptContext { + ec.calg = jwa.A256GCM() + ec.compression = jwa.NoCompress() + ec.format = fmtCompact + ec.builders = ec.builders[:0] + ec.protected = nil + return ec +} + +func (ec *encryptContext) ProcessOptions(options []EncryptOption) error { + var mergeProtected bool + var useRawCEK bool + for _, option := range options { + switch option.Ident() { + case identKey{}: + var wk *withKey + if err := option.Value(&wk); err != nil { + return fmt.Errorf("jwe.encrypt: WithKey must be a *withKey: %w", err) + } + v, ok := wk.alg.(jwa.KeyEncryptionAlgorithm) + if !ok { + return fmt.Errorf("jwe.encrypt: WithKey() option must be specified using jwa.KeyEncryptionAlgorithm (got %T)", wk.alg) + } + if v == jwa.DIRECT() || v == jwa.ECDH_ES() { + useRawCEK = true + } + ec.builders = append(ec.builders, &recipientBuilder{alg: v, key: wk.key, headers: wk.headers}) + case identContentEncryptionAlgorithm{}: + var c jwa.ContentEncryptionAlgorithm + if err := option.Value(&c); err != nil { + return err + } + ec.calg = c + case identCompress{}: + var comp jwa.CompressionAlgorithm + if err := option.Value(&comp); err != nil { + return err + } + ec.compression = comp + case identMergeProtectedHeaders{}: + var mp bool + if err := option.Value(&mp); err != nil { + return err + } + mergeProtected = mp + case identProtectedHeaders{}: + var hdrs Headers + if err := option.Value(&hdrs); err != nil { + return err + } + if !mergeProtected || ec.protected == nil { + ec.protected = hdrs + } else { + merged, err := ec.protected.Merge(hdrs) + if err != nil { + return fmt.Errorf(`failed to merge headers: %w`, err) + } + ec.protected = merged + } + case identSerialization{}: + var fmtOpt int + if err := option.Value(&fmtOpt); err != nil { + return err + } + ec.format = fmtOpt + } + } + + // We need to have at least one builder + switch l := len(ec.builders); { + case l == 0: + return fmt.Errorf(`missing key encryption builders: use jwe.WithKey() to specify one`) + case l > 1: + if ec.format == fmtCompact { + return fmt.Errorf(`cannot use compact serialization when multiple recipients exist (check the number of WithKey() argument, or use WithJSON())`) + } + } + + if useRawCEK { + if len(ec.builders) != 1 { + return fmt.Errorf(`multiple recipients for ECDH-ES/DIRECT mode supported`) + } + } + + return nil +} + +var msgPool = pool.New(allocMessage, freeMessage) + +func allocMessage() *Message { + return &Message{ + recipients: make([]Recipient, 0, 1), + } +} + +func freeMessage(msg *Message) *Message { + msg.cipherText = nil + msg.initializationVector = nil + if hdr := msg.protectedHeaders; hdr != nil { + headerPool.Put(hdr) + } + msg.protectedHeaders = nil + msg.unprotectedHeaders = nil + msg.recipients = nil // reuse should be done elsewhere + msg.authenticatedData = nil + msg.tag = nil + msg.rawProtectedHeaders = nil + msg.storeProtectedHeaders = false + return msg +} + +var headerPool = pool.New(NewHeaders, freeHeaders) + +func freeHeaders(h Headers) Headers { + if c, ok := h.(interface{ clear() }); ok { + c.clear() + } + return h +} + +var recipientPool = pool.New(NewRecipient, freeRecipient) + +func freeRecipient(r Recipient) Recipient { + if h := r.Headers(); h != nil { + if c, ok := h.(interface{ clear() }); ok { + c.clear() + } + } + + if sr, ok := r.(*stdRecipient); ok { + sr.encryptedKey = nil + } + return r +} + +var recipientSlicePool = pool.NewSlicePool(allocRecipientSlice, freeRecipientSlice) + +func allocRecipientSlice() []Recipient { + return make([]Recipient, 0, 1) +} + +func freeRecipientSlice(rs []Recipient) []Recipient { + for _, r := range rs { + recipientPool.Put(r) + } + return rs[:0] +} + +func (ec *encryptContext) EncryptMessage(payload []byte, cek []byte) ([]byte, error) { + // Get protected headers from pool and copy contents from context + protected := headerPool.Get() + if userSupplied := ec.protected; userSupplied != nil { + ec.protected = nil // Clear from context + if err := userSupplied.Copy(protected); err != nil { + return nil, fmt.Errorf(`failed to copy protected headers: %w`, err) + } + } + + // There is exactly one content encrypter. + contentcrypt, err := content_crypt.NewGeneric(ec.calg) + if err != nil { + return nil, fmt.Errorf(`failed to create AES encrypter: %w`, err) + } + + // Generate CEK if not provided + if len(cek) <= 0 { + bk, err := keygen.Random(contentcrypt.KeySize()) + if err != nil { + return nil, fmt.Errorf(`failed to generate key: %w`, err) + } + cek = bk.Bytes() + } + + var useRawCEK bool + for _, builder := range ec.builders { + if builder.alg == jwa.DIRECT() || builder.alg == jwa.ECDH_ES() { + useRawCEK = true + break + } + } + + recipients := recipientSlicePool.GetCapacity(len(ec.builders)) + defer recipientSlicePool.Put(recipients) + + for i, builder := range ec.builders { + r := recipientPool.Get() + defer recipientPool.Put(r) + + // some builders require hint from the contentcrypt object + rawCEK, err := builder.Build(r, cek, ec.calg, contentcrypt) + if err != nil { + return nil, fmt.Errorf(`failed to create recipient #%d: %w`, i, err) + } + recipients = append(recipients, r) + + // Kinda feels weird, but if useRawCEK == true, we asserted earlier + // that len(builders) == 1, so this is OK + if useRawCEK { + cek = rawCEK + } + } + + if err := protected.Set(ContentEncryptionKey, ec.calg); err != nil { + return nil, fmt.Errorf(`failed to set "enc" in protected header: %w`, err) + } + + if ec.compression != jwa.NoCompress() { + payload, err = compress(payload) + if err != nil { + return nil, fmt.Errorf(`failed to compress payload before encryption: %w`, err) + } + if err := protected.Set(CompressionKey, ec.compression); err != nil { + return nil, fmt.Errorf(`failed to set "zip" in protected header: %w`, err) + } + } + + // If there's only one recipient, you want to include that in the + // protected header + if len(recipients) == 1 { + h, err := protected.Merge(recipients[0].Headers()) + if err != nil { + return nil, fmt.Errorf(`failed to merge protected headers: %w`, err) + } + protected = h + } + + aad, err := protected.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to base64 encode protected headers: %w`, err) + } + + iv, ciphertext, tag, err := contentcrypt.Encrypt(cek, payload, aad) + if err != nil { + return nil, fmt.Errorf(`failed to encrypt payload: %w`, err) + } + + msg := msgPool.Get() + defer msgPool.Put(msg) + + if err := msg.Set(CipherTextKey, ciphertext); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, CipherTextKey, err) + } + if err := msg.Set(InitializationVectorKey, iv); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, InitializationVectorKey, err) + } + if err := msg.Set(ProtectedHeadersKey, protected); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, ProtectedHeadersKey, err) + } + if err := msg.Set(RecipientsKey, recipients); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, RecipientsKey, err) + } + if err := msg.Set(TagKey, tag); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, TagKey, err) + } + + switch ec.format { + case fmtCompact: + return Compact(msg) + case fmtJSON: + return json.Marshal(msg) + case fmtJSONPretty: + return json.MarshalIndent(msg, "", " ") + default: + return nil, fmt.Errorf(`invalid serialization`) + } +} + +// Decrypt takes encrypted payload, and information required to decrypt the +// payload (e.g. the key encryption algorithm and the corresponding +// key to decrypt the JWE message) in its optional arguments. See +// the examples and list of options that return a DecryptOption for possible +// values. Upon successful decryptiond returns the decrypted payload. +// +// The JWE message can be either compact or full JSON format. +// +// When using `jwe.WithKeyEncryptionAlgorithm()`, you can pass a `jwa.KeyAlgorithm` +// for convenience: this is mainly to allow you to directly pass the result of `(jwk.Key).Algorithm()`. +// However, do note that while `(jwk.Key).Algorithm()` could very well contain key encryption +// algorithms, it could also contain other types of values, such as _signature algorithms_. +// In order for `jwe.Decrypt` to work properly, the `alg` parameter must be of type +// `jwa.KeyEncryptionAlgorithm` or otherwise it will cause an error. +// +// When using `jwe.WithKey()`, the value must be a private key. +// It can be either in its raw format (e.g. *rsa.PrivateKey) or a jwk.Key +// +// When the encrypted message is also compressed, the decompressed payload must be +// smaller than the size specified by the `jwe.WithMaxDecompressBufferSize` setting, +// which defaults to 10MB. If the decompressed payload is larger than this size, +// an error is returned. +// +// You can opt to change the MaxDecompressBufferSize setting globally, or on a +// per-call basis by passing the `jwe.WithMaxDecompressBufferSize` option to +// either `jwe.Settings()` or `jwe.Decrypt()`: +// +// jwe.Settings(jwe.WithMaxDecompressBufferSize(10*1024*1024)) // changes value globally +// jwe.Decrypt(..., jwe.WithMaxDecompressBufferSize(250*1024)) // changes just for this call +func Decrypt(buf []byte, options ...DecryptOption) ([]byte, error) { + dc := decryptContextPool.Get() + defer decryptContextPool.Put(dc) + + if err := dc.ProcessOptions(options); err != nil { + return nil, decryptError{fmt.Errorf(`jwe.Decrypt: failed to process options: %w`, err)} + } + + ret, err := dc.DecryptMessage(buf) + if err != nil { + return nil, decryptError{fmt.Errorf(`jwe.Decrypt: %w`, err)} + } + return ret, nil +} + +// Parse parses the JWE message into a Message object. The JWE message +// can be either compact or full JSON format. +// +// Parse() currently does not take any options, but the API accepts it +// in anticipation of future addition. +func Parse(buf []byte, _ ...ParseOption) (*Message, error) { + return parseJSONOrCompact(buf, false) +} + +// errors are wrapped within this function, because we call it directly +// from Decrypt as well. +func parseJSONOrCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) { + buf = bytes.TrimSpace(buf) + if len(buf) == 0 { + return nil, parseError{fmt.Errorf(`jwe.Parse: empty buffer`)} + } + + var msg *Message + var err error + if buf[0] == tokens.OpenCurlyBracket { + msg, err = parseJSON(buf, storeProtectedHeaders) + } else { + msg, err = parseCompact(buf, storeProtectedHeaders) + } + + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.Parse: %w`, err)} + } + return msg, nil +} + +// ParseString is the same as Parse, but takes a string. +func ParseString(s string) (*Message, error) { + msg, err := Parse([]byte(s)) + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.ParseString: %w`, err)} + } + return msg, nil +} + +// ParseReader is the same as Parse, but takes an io.Reader. +func ParseReader(src io.Reader) (*Message, error) { + buf, err := io.ReadAll(src) + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.ParseReader: failed to read from io.Reader: %w`, err)} + } + msg, err := Parse(buf) + if err != nil { + return nil, parseError{fmt.Errorf(`jwe.ParseReader: %w`, err)} + } + return msg, nil +} + +func parseJSON(buf []byte, storeProtectedHeaders bool) (*Message, error) { + m := NewMessage() + m.storeProtectedHeaders = storeProtectedHeaders + if err := json.Unmarshal(buf, &m); err != nil { + return nil, fmt.Errorf(`failed to parse JSON: %w`, err) + } + return m, nil +} + +func parseCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) { + var parts [5][]byte + var ok bool + + for i := range 4 { + parts[i], buf, ok = bytes.Cut(buf, []byte{tokens.Period}) + if !ok { + return nil, fmt.Errorf(`compact JWE format must have five parts (%d)`, i+1) + } + } + // Validate that the last part does not contain more dots + if bytes.ContainsRune(buf, tokens.Period) { + return nil, errors.New(`compact JWE format must have five parts, not more`) + } + parts[4] = buf + + hdrbuf, err := base64.Decode(parts[0]) + if err != nil { + return nil, fmt.Errorf(`failed to parse first part of compact form: %w`, err) + } + + protected := NewHeaders() + if err := json.Unmarshal(hdrbuf, protected); err != nil { + return nil, fmt.Errorf(`failed to parse header JSON: %w`, err) + } + + ivbuf, err := base64.Decode(parts[2]) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode iv: %w`, err) + } + + ctbuf, err := base64.Decode(parts[3]) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode content: %w`, err) + } + + tagbuf, err := base64.Decode(parts[4]) + if err != nil { + return nil, fmt.Errorf(`failed to base64 decode tag: %w`, err) + } + + m := NewMessage() + if err := m.Set(CipherTextKey, ctbuf); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, CipherTextKey, err) + } + if err := m.Set(InitializationVectorKey, ivbuf); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, InitializationVectorKey, err) + } + if err := m.Set(ProtectedHeadersKey, protected); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, ProtectedHeadersKey, err) + } + + if err := m.makeDummyRecipient(string(parts[1]), protected); err != nil { + return nil, fmt.Errorf(`failed to setup recipient: %w`, err) + } + + if err := m.Set(TagKey, tagbuf); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, TagKey, err) + } + + if storeProtectedHeaders { + // This is later used for decryption. + m.rawProtectedHeaders = parts[0] + } + + return m, nil +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jws.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = hdr.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC1123 format string: +// +// jwe.RegisterCustomField(`x-birthday`, jwe.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC1123, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/BUILD.bazel new file mode 100644 index 0000000000..c410a05cdf --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/BUILD.bazel @@ -0,0 +1,43 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwebb", + srcs = [ + "content_cipher.go", + "key_decrypt_asymmetric.go", + "key_decrypt_symmetric.go", + "key_encrypt_asymmetric.go", + "key_encrypt_symmetric.go", + "key_encryption.go", + "keywrap.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwe/jwebb", + visibility = ["//jwe:__subpackages__"], + deps = [ + "//internal/keyconv", + "//internal/pool", + "//jwe/internal/cipher", + "//jwe/internal/concatkdf", + "//jwe/internal/content_crypt", + "//jwe/internal/keygen", + "//internal/tokens", + "@org_golang_x_crypto//pbkdf2", + ], +) + +go_test( + name = "jwebb_test", + srcs = [ + "decrypt_test.go", + "jwebb_test.go", + "keywrap_test.go", + ], + embed = [":jwebb"], + deps = [ + "//internal/jwxtest", + "//jwa", + "//jwe/internal/keygen", + "//internal/tokens", + "@com_github_stretchr_testify//require", + ], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/content_cipher.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/content_cipher.go new file mode 100644 index 0000000000..9078789d8d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/content_cipher.go @@ -0,0 +1,34 @@ +package jwebb + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/cipher" + "github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt" +) + +// ContentEncryptionIsSupported checks if the content encryption algorithm is supported +func ContentEncryptionIsSupported(alg string) bool { + switch alg { + case tokens.A128GCM, tokens.A192GCM, tokens.A256GCM, + tokens.A128CBC_HS256, tokens.A192CBC_HS384, tokens.A256CBC_HS512: + return true + default: + return false + } +} + +// CreateContentCipher creates a content encryption cipher for the given algorithm string +func CreateContentCipher(alg string) (content_crypt.Cipher, error) { + if !ContentEncryptionIsSupported(alg) { + return nil, fmt.Errorf(`invalid content cipher algorithm (%s)`, alg) + } + + cipher, err := cipher.NewAES(alg) + if err != nil { + return nil, fmt.Errorf(`failed to build content cipher for %s: %w`, alg, err) + } + + return cipher, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/jwebb.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/jwebb.go new file mode 100644 index 0000000000..3768acef8b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/jwebb.go @@ -0,0 +1,15 @@ +// Package jwebb provides the building blocks (hence the name "bb") for JWE operations. +// It should be thought of as a low-level API, almost akin to internal packages +// that should not be used directly by users of the jwx package. However, these exist +// to provide a more efficient way to perform JWE operations without the overhead of +// the higher-level jwe package to power-users who know what they are doing. +// +// This package is currently considered EXPERIMENTAL, and the API may change +// without notice. It is not recommended to use this package unless you are +// fully aware of the implications of using it. +// +// All bb packages in jwx follow the same design principles: +// 1. Does minimal checking of input parameters (for performance); callers need to ensure that the parameters are valid. +// 2. All exported functions are stringly typed (i.e. they do not take any parameters unless they absolutely have to). +// 3. Does not rely on other public jwx packages (they are standalone, except for internal packages). +package jwebb diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_asymmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_asymmetric.go new file mode 100644 index 0000000000..ac07993176 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_asymmetric.go @@ -0,0 +1,177 @@ +package jwebb + +import ( + "crypto" + "crypto/aes" + "crypto/ecdh" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/binary" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +func contentEncryptionKeySize(ctalg string) (uint32, error) { + switch ctalg { + case tokens.A128GCM: + return tokens.KeySize16, nil + case tokens.A192GCM: + return tokens.KeySize24, nil + case tokens.A256GCM: + return tokens.KeySize32, nil + case tokens.A128CBC_HS256: + return tokens.KeySize32, nil + case tokens.A192CBC_HS384: + return tokens.KeySize48, nil + case tokens.A256CBC_HS512: + return tokens.KeySize64, nil + default: + return 0, fmt.Errorf(`unsupported content encryption algorithm %s`, ctalg) + } +} + +func KeyEncryptionECDHESKeySize(alg, ctalg string) (string, uint32, bool, error) { + switch alg { + case tokens.ECDH_ES: + keysize, err := contentEncryptionKeySize(ctalg) + if err != nil { + return "", 0, false, err + } + return ctalg, keysize, false, nil + case tokens.ECDH_ES_A128KW: + return alg, tokens.KeySize16, true, nil + case tokens.ECDH_ES_A192KW: + return alg, tokens.KeySize24, true, nil + case tokens.ECDH_ES_A256KW: + return alg, tokens.KeySize32, true, nil + default: + return "", 0, false, fmt.Errorf(`unsupported key encryption algorithm %s`, alg) + } +} + +func DeriveECDHES(alg string, apu, apv []byte, privkeyif, pubkeyif any, keysize uint32) ([]byte, error) { + pubinfo := make([]byte, 4) + binary.BigEndian.PutUint32(pubinfo, keysize*tokens.BitsPerByte) + + var privkey *ecdh.PrivateKey + var pubkey *ecdh.PublicKey + if err := keyconv.ECDHPrivateKey(&privkey, privkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: %w`, err) + } + if err := keyconv.ECDHPublicKey(&pubkey, pubkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: %w`, err) + } + + zBytes, err := privkey.ECDH(pubkey) + if err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: unable to determine Z: %w`, err) + } + kdf := concatkdf.New(crypto.SHA256, []byte(alg), zBytes, apu, apv, pubinfo, []byte{}) + key := make([]byte, keysize) + if _, err := kdf.Read(key); err != nil { + return nil, fmt.Errorf(`jwebb.DeriveECDHES: failed to read kdf: %w`, err) + } + + return key, nil +} + +func KeyDecryptECDHESKeyWrap(_, enckey []byte, alg string, apu, apv []byte, privkey, pubkey any, keysize uint32) ([]byte, error) { + key, err := DeriveECDHES(alg, apu, apv, privkey, pubkey, keysize) + if err != nil { + return nil, fmt.Errorf(`failed to derive ECDHES encryption key: %w`, err) + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher for ECDH-ES key wrap: %w`, err) + } + + return Unwrap(block, enckey) +} + +func KeyDecryptECDHES(_, _ []byte, alg string, apu, apv []byte, privkey, pubkey any, keysize uint32) ([]byte, error) { + key, err := DeriveECDHES(alg, apu, apv, privkey, pubkey, keysize) + if err != nil { + return nil, fmt.Errorf(`failed to derive ECDHES encryption key: %w`, err) + } + return key, nil +} + +// RSA key decryption functions + +func KeyDecryptRSA15(_, enckey []byte, privkeyif any, keysize int) ([]byte, error) { + var privkey *rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, privkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.KeyDecryptRSA15: %w`, err) + } + + // Perform some input validation. + expectedlen := privkey.PublicKey.N.BitLen() / tokens.BitsPerByte + if expectedlen != len(enckey) { + // Input size is incorrect, the encrypted payload should always match + // the size of the public modulus (e.g. using a 2048 bit key will + // produce 256 bytes of output). Reject this since it's invalid input. + return nil, fmt.Errorf( + "input size for key decrypt is incorrect (expected %d, got %d)", + expectedlen, + len(enckey), + ) + } + + // Generate a random CEK of the required size + bk, err := keygen.Random(keysize * tokens.RSAKeyGenMultiplier) + if err != nil { + return nil, fmt.Errorf(`failed to generate key`) + } + cek := bk.Bytes() + + // Use a defer/recover pattern to handle potential panics from DecryptPKCS1v15SessionKey + defer func() { + // DecryptPKCS1v15SessionKey sometimes panics on an invalid payload + // because of an index out of bounds error, which we want to ignore. + // This has been fixed in Go 1.3.1 (released 2014/08/13), the recover() + // only exists for preventing crashes with unpatched versions. + // See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k + // See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33 + _ = recover() + }() + + // When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to + // prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing + // the Million Message Attack on Cryptographic Message Syntax". We are + // therefore deliberately ignoring errors here. + _ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, privkey, enckey, cek) + + return cek, nil +} + +func KeyDecryptRSAOAEP(_, enckey []byte, alg string, privkeyif any) ([]byte, error) { + var privkey *rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, privkeyif); err != nil { + return nil, fmt.Errorf(`jwebb.KeyDecryptRSAOAEP: %w`, err) + } + + var hash hash.Hash + switch alg { + case tokens.RSA_OAEP: + hash = sha1.New() + case tokens.RSA_OAEP_256: + hash = sha256.New() + case tokens.RSA_OAEP_384: + hash = sha512.New384() + case tokens.RSA_OAEP_512: + hash = sha512.New() + default: + return nil, fmt.Errorf(`failed to generate key encrypter for RSA-OAEP: RSA_OAEP/RSA_OAEP_256/RSA_OAEP_384/RSA_OAEP_512 required`) + } + + return rsa.DecryptOAEP(hash, rand.Reader, privkey, enckey, []byte{}) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_symmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_symmetric.go new file mode 100644 index 0000000000..c09e30a34e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_decrypt_symmetric.go @@ -0,0 +1,91 @@ +package jwebb + +import ( + "crypto/aes" + cryptocipher "crypto/cipher" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "golang.org/x/crypto/pbkdf2" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// AES key wrap decryption functions + +// Use constants from tokens package +// No need to redefine them here + +func KeyDecryptAESKW(_, enckey []byte, _ string, sharedkey []byte) ([]byte, error) { + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher from shared key: %w`, err) + } + + cek, err := Unwrap(block, enckey) + if err != nil { + return nil, fmt.Errorf(`failed to unwrap data: %w`, err) + } + return cek, nil +} + +func KeyDecryptDirect(_, _ []byte, _ string, cek []byte) ([]byte, error) { + return cek, nil +} + +func KeyDecryptPBES2(_, enckey []byte, alg string, password []byte, salt []byte, count int) ([]byte, error) { + var hashFunc func() hash.Hash + var keylen int + + switch alg { + case tokens.PBES2_HS256_A128KW: + hashFunc = sha256.New + keylen = tokens.KeySize16 + case tokens.PBES2_HS384_A192KW: + hashFunc = sha512.New384 + keylen = tokens.KeySize24 + case tokens.PBES2_HS512_A256KW: + hashFunc = sha512.New + keylen = tokens.KeySize32 + default: + return nil, fmt.Errorf(`unsupported PBES2 algorithm: %s`, alg) + } + + // Derive key using PBKDF2 + derivedKey := pbkdf2.Key(password, salt, count, keylen, hashFunc) + + // Use the derived key for AES key wrap + return KeyDecryptAESKW(nil, enckey, alg, derivedKey) +} + +func KeyDecryptAESGCMKW(recipientKey, _ []byte, _ string, sharedkey []byte, iv []byte, tag []byte) ([]byte, error) { + if len(iv) != tokens.GCMIVSize { + return nil, fmt.Errorf("GCM requires 96-bit iv, got %d", len(iv)*tokens.BitsPerByte) + } + if len(tag) != tokens.GCMTagSize { + return nil, fmt.Errorf("GCM requires 128-bit tag, got %d", len(tag)*tokens.BitsPerByte) + } + + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create new AES cipher: %w`, err) + } + + aesgcm, err := cryptocipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf(`failed to create new GCM wrap: %w`, err) + } + + // Combine recipient key and tag for GCM decryption + ciphertext := recipientKey[:] + ciphertext = append(ciphertext, tag...) + + jek, err := aesgcm.Open(nil, iv, ciphertext, nil) + if err != nil { + return nil, fmt.Errorf(`failed to decode key: %w`, err) + } + + return jek, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_asymmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_asymmetric.go new file mode 100644 index 0000000000..6f008173c8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_asymmetric.go @@ -0,0 +1,147 @@ +package jwebb + +import ( + "crypto/aes" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// KeyEncryptRSA15 encrypts the CEK using RSA PKCS#1 v1.5 +func KeyEncryptRSA15(cek []byte, _ string, pubkey *rsa.PublicKey) (keygen.ByteSource, error) { + encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey, cek) + if err != nil { + return nil, fmt.Errorf(`failed to encrypt using PKCS1v15: %w`, err) + } + return keygen.ByteKey(encrypted), nil +} + +// KeyEncryptRSAOAEP encrypts the CEK using RSA OAEP +func KeyEncryptRSAOAEP(cek []byte, alg string, pubkey *rsa.PublicKey) (keygen.ByteSource, error) { + var hash hash.Hash + switch alg { + case tokens.RSA_OAEP: + hash = sha1.New() + case tokens.RSA_OAEP_256: + hash = sha256.New() + case tokens.RSA_OAEP_384: + hash = sha512.New384() + case tokens.RSA_OAEP_512: + hash = sha512.New() + default: + return nil, fmt.Errorf(`failed to generate key encrypter for RSA-OAEP: RSA_OAEP/RSA_OAEP_256/RSA_OAEP_384/RSA_OAEP_512 required`) + } + + encrypted, err := rsa.EncryptOAEP(hash, rand.Reader, pubkey, cek, []byte{}) + if err != nil { + return nil, fmt.Errorf(`failed to OAEP encrypt: %w`, err) + } + return keygen.ByteKey(encrypted), nil +} + +// generateECDHESKeyECDSA generates the key material for ECDSA keys using ECDH-ES +func generateECDHESKeyECDSA(alg string, calg string, keysize uint32, pubkey *ecdsa.PublicKey, apu, apv []byte) (keygen.ByteWithECPublicKey, error) { + // Generate the key directly + kg, err := keygen.Ecdhes(alg, calg, int(keysize), pubkey, apu, apv) + if err != nil { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`failed to generate ECDSA key: %w`, err) + } + + bwpk, ok := kg.(keygen.ByteWithECPublicKey) + if !ok { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`key generator generated invalid key (expected ByteWithECPublicKey)`) + } + + return bwpk, nil +} + +// generateECDHESKeyX25519 generates the key material for X25519 keys using ECDH-ES +func generateECDHESKeyX25519(alg string, calg string, keysize uint32, pubkey *ecdh.PublicKey) (keygen.ByteWithECPublicKey, error) { + // Generate the key directly + kg, err := keygen.X25519(alg, calg, int(keysize), pubkey) + if err != nil { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`failed to generate X25519 key: %w`, err) + } + + bwpk, ok := kg.(keygen.ByteWithECPublicKey) + if !ok { + return keygen.ByteWithECPublicKey{}, fmt.Errorf(`key generator generated invalid key (expected ByteWithECPublicKey)`) + } + + return bwpk, nil +} + +// KeyEncryptECDHESKeyWrapECDSA encrypts the CEK using ECDH-ES with key wrapping for ECDSA keys +func KeyEncryptECDHESKeyWrapECDSA(cek []byte, alg string, apu, apv []byte, pubkey *ecdsa.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyECDSA(alg, calg, keysize, pubkey, apu, apv) + if err != nil { + return nil, err + } + + // For key wrapping algorithms, wrap the CEK with the generated key + block, err := aes.NewCipher(bwpk.Bytes()) + if err != nil { + return nil, fmt.Errorf(`failed to generate cipher from generated key: %w`, err) + } + + jek, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + + bwpk.ByteKey = keygen.ByteKey(jek) + return bwpk, nil +} + +// KeyEncryptECDHESKeyWrapX25519 encrypts the CEK using ECDH-ES with key wrapping for X25519 keys +func KeyEncryptECDHESKeyWrapX25519(cek []byte, alg string, _ []byte, _ []byte, pubkey *ecdh.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyX25519(alg, calg, keysize, pubkey) + if err != nil { + return nil, err + } + + // For key wrapping algorithms, wrap the CEK with the generated key + block, err := aes.NewCipher(bwpk.Bytes()) + if err != nil { + return nil, fmt.Errorf(`failed to generate cipher from generated key: %w`, err) + } + + jek, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + + bwpk.ByteKey = keygen.ByteKey(jek) + return bwpk, nil +} + +// KeyEncryptECDHESECDSA encrypts using ECDH-ES direct (no key wrapping) for ECDSA keys +func KeyEncryptECDHESECDSA(_ []byte, alg string, apu, apv []byte, pubkey *ecdsa.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyECDSA(alg, calg, keysize, pubkey, apu, apv) + if err != nil { + return nil, err + } + + // For direct ECDH-ES, return the generated key directly + return bwpk, nil +} + +// KeyEncryptECDHESX25519 encrypts using ECDH-ES direct (no key wrapping) for X25519 keys +func KeyEncryptECDHESX25519(_ []byte, alg string, _, _ []byte, pubkey *ecdh.PublicKey, keysize uint32, calg string) (keygen.ByteSource, error) { + bwpk, err := generateECDHESKeyX25519(alg, calg, keysize, pubkey) + if err != nil { + return nil, err + } + + // For direct ECDH-ES, return the generated key directly + return bwpk, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_symmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_symmetric.go new file mode 100644 index 0000000000..d489aaba28 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encrypt_symmetric.go @@ -0,0 +1,115 @@ +package jwebb + +import ( + "crypto/aes" + cryptocipher "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + "io" + + "golang.org/x/crypto/pbkdf2" + + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwe/internal/keygen" +) + +// KeyEncryptAESKW encrypts the CEK using AES key wrap +func KeyEncryptAESKW(cek []byte, _ string, sharedkey []byte) (keygen.ByteSource, error) { + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher from shared key: %w`, err) + } + + encrypted, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + return keygen.ByteKey(encrypted), nil +} + +// KeyEncryptDirect returns the CEK directly for DIRECT algorithm +func KeyEncryptDirect(_ []byte, _ string, sharedkey []byte) (keygen.ByteSource, error) { + return keygen.ByteKey(sharedkey), nil +} + +// KeyEncryptPBES2 encrypts the CEK using PBES2 password-based encryption +func KeyEncryptPBES2(cek []byte, alg string, password []byte) (keygen.ByteSource, error) { + var hashFunc func() hash.Hash + var keylen int + + switch alg { + case tokens.PBES2_HS256_A128KW: + hashFunc = sha256.New + keylen = tokens.KeySize16 + case tokens.PBES2_HS384_A192KW: + hashFunc = sha512.New384 + keylen = tokens.KeySize24 + case tokens.PBES2_HS512_A256KW: + hashFunc = sha512.New + keylen = tokens.KeySize32 + default: + return nil, fmt.Errorf(`unsupported PBES2 algorithm: %s`, alg) + } + + count := tokens.PBES2DefaultIterations + salt := make([]byte, keylen) + _, err := io.ReadFull(rand.Reader, salt) + if err != nil { + return nil, fmt.Errorf(`failed to get random salt: %w`, err) + } + + fullsalt := []byte(alg) + fullsalt = append(fullsalt, byte(tokens.PBES2NullByteSeparator)) + fullsalt = append(fullsalt, salt...) + + // Derive key using PBKDF2 + derivedKey := pbkdf2.Key(password, fullsalt, count, keylen, hashFunc) + + // Use the derived key for AES key wrap + block, err := aes.NewCipher(derivedKey) + if err != nil { + return nil, fmt.Errorf(`failed to create cipher from derived key: %w`, err) + } + encrypted, err := Wrap(block, cek) + if err != nil { + return nil, fmt.Errorf(`failed to wrap data: %w`, err) + } + + return keygen.ByteWithSaltAndCount{ + ByteKey: encrypted, + Salt: salt, + Count: count, + }, nil +} + +// KeyEncryptAESGCMKW encrypts the CEK using AES GCM key wrap +func KeyEncryptAESGCMKW(cek []byte, _ string, sharedkey []byte) (keygen.ByteSource, error) { + block, err := aes.NewCipher(sharedkey) + if err != nil { + return nil, fmt.Errorf(`failed to create new AES cipher: %w`, err) + } + + aesgcm, err := cryptocipher.NewGCM(block) + if err != nil { + return nil, fmt.Errorf(`failed to create new GCM wrap: %w`, err) + } + + iv := make([]byte, aesgcm.NonceSize()) + _, err = io.ReadFull(rand.Reader, iv) + if err != nil { + return nil, fmt.Errorf(`failed to get random iv: %w`, err) + } + + encrypted := aesgcm.Seal(nil, iv, cek, nil) + tag := encrypted[len(encrypted)-aesgcm.Overhead():] + ciphertext := encrypted[:len(encrypted)-aesgcm.Overhead()] + + return keygen.ByteWithIVAndTag{ + ByteKey: ciphertext, + IV: iv, + Tag: tag, + }, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encryption.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encryption.go new file mode 100644 index 0000000000..ce39352fc5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/key_encryption.go @@ -0,0 +1,70 @@ +package jwebb + +import ( + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// IsECDHES checks if the algorithm is an ECDH-ES based algorithm +func IsECDHES(alg string) bool { + switch alg { + case tokens.ECDH_ES, tokens.ECDH_ES_A128KW, tokens.ECDH_ES_A192KW, tokens.ECDH_ES_A256KW: + return true + default: + return false + } +} + +// IsRSA15 checks if the algorithm is RSA1_5 +func IsRSA15(alg string) bool { + return alg == tokens.RSA1_5 +} + +// IsRSAOAEP checks if the algorithm is an RSA-OAEP based algorithm +func IsRSAOAEP(alg string) bool { + switch alg { + case tokens.RSA_OAEP, tokens.RSA_OAEP_256, tokens.RSA_OAEP_384, tokens.RSA_OAEP_512: + return true + default: + return false + } +} + +// IsAESKW checks if the algorithm is an AES key wrap algorithm +func IsAESKW(alg string) bool { + switch alg { + case tokens.A128KW, tokens.A192KW, tokens.A256KW: + return true + default: + return false + } +} + +// IsAESGCMKW checks if the algorithm is an AES-GCM key wrap algorithm +func IsAESGCMKW(alg string) bool { + switch alg { + case tokens.A128GCMKW, tokens.A192GCMKW, tokens.A256GCMKW: + return true + default: + return false + } +} + +// IsPBES2 checks if the algorithm is a PBES2 based algorithm +func IsPBES2(alg string) bool { + switch alg { + case tokens.PBES2_HS256_A128KW, tokens.PBES2_HS384_A192KW, tokens.PBES2_HS512_A256KW: + return true + default: + return false + } +} + +// IsDirect checks if the algorithm is direct encryption +func IsDirect(alg string) bool { + return alg == tokens.DIRECT +} + +// IsSymmetric checks if the algorithm is a symmetric key encryption algorithm +func IsSymmetric(alg string) bool { + return IsAESKW(alg) || IsAESGCMKW(alg) || IsPBES2(alg) || IsDirect(alg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/keywrap.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/keywrap.go new file mode 100644 index 0000000000..0792d6cb8e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/jwebb/keywrap.go @@ -0,0 +1,110 @@ +package jwebb + +import ( + "crypto/cipher" + "crypto/subtle" + "encoding/binary" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +var keywrapDefaultIV = []byte{0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6} + +func Wrap(kek cipher.Block, cek []byte) ([]byte, error) { + if len(cek)%tokens.KeywrapBlockSize != 0 { + return nil, fmt.Errorf(`keywrap input must be %d byte blocks`, tokens.KeywrapBlockSize) + } + + n := len(cek) / tokens.KeywrapChunkLen + r := make([][]byte, n) + + for i := range n { + r[i] = make([]byte, tokens.KeywrapChunkLen) + copy(r[i], cek[i*tokens.KeywrapChunkLen:]) + } + + buffer := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen * 2) + defer pool.ByteSlice().Put(buffer) + // the byte slice has the capacity, but len is 0 + buffer = buffer[:tokens.KeywrapChunkLen*2] + + tBytes := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen) + defer pool.ByteSlice().Put(tBytes) + // the byte slice has the capacity, but len is 0 + tBytes = tBytes[:tokens.KeywrapChunkLen] + + copy(buffer, keywrapDefaultIV) + + for t := range tokens.KeywrapRounds * n { + copy(buffer[tokens.KeywrapChunkLen:], r[t%n]) + + kek.Encrypt(buffer, buffer) + + binary.BigEndian.PutUint64(tBytes, uint64(t+1)) + + for i := range tokens.KeywrapChunkLen { + buffer[i] = buffer[i] ^ tBytes[i] + } + copy(r[t%n], buffer[tokens.KeywrapChunkLen:]) + } + + out := make([]byte, (n+1)*tokens.KeywrapChunkLen) + copy(out, buffer[:tokens.KeywrapChunkLen]) + for i := range r { + copy(out[(i+1)*tokens.KeywrapBlockSize:], r[i]) + } + + return out, nil +} + +func Unwrap(block cipher.Block, ciphertxt []byte) ([]byte, error) { + if len(ciphertxt)%tokens.KeywrapChunkLen != 0 { + return nil, fmt.Errorf(`keyunwrap input must be %d byte blocks`, tokens.KeywrapChunkLen) + } + + n := (len(ciphertxt) / tokens.KeywrapChunkLen) - 1 + r := make([][]byte, n) + + for i := range r { + r[i] = make([]byte, tokens.KeywrapChunkLen) + copy(r[i], ciphertxt[(i+1)*tokens.KeywrapChunkLen:]) + } + + buffer := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen * 2) + defer pool.ByteSlice().Put(buffer) + // the byte slice has the capacity, but len is 0 + buffer = buffer[:tokens.KeywrapChunkLen*2] + + tBytes := pool.ByteSlice().GetCapacity(tokens.KeywrapChunkLen) + defer pool.ByteSlice().Put(tBytes) + // the byte slice has the capacity, but len is 0 + tBytes = tBytes[:tokens.KeywrapChunkLen] + + copy(buffer[:tokens.KeywrapChunkLen], ciphertxt[:tokens.KeywrapChunkLen]) + + for t := tokens.KeywrapRounds*n - 1; t >= 0; t-- { + binary.BigEndian.PutUint64(tBytes, uint64(t+1)) + + for i := range tokens.KeywrapChunkLen { + buffer[i] = buffer[i] ^ tBytes[i] + } + copy(buffer[tokens.KeywrapChunkLen:], r[t%n]) + + block.Decrypt(buffer, buffer) + + copy(r[t%n], buffer[tokens.KeywrapChunkLen:]) + } + + if subtle.ConstantTimeCompare(buffer[:tokens.KeywrapChunkLen], keywrapDefaultIV) == 0 { + return nil, fmt.Errorf(`key unwrap: failed to unwrap key`) + } + + out := make([]byte, n*tokens.KeywrapChunkLen) + for i := range r { + copy(out[i*tokens.KeywrapChunkLen:], r[i]) + } + + return out, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/key_provider.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/key_provider.go new file mode 100644 index 0000000000..05adc04517 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/key_provider.go @@ -0,0 +1,163 @@ +package jwe + +import ( + "context" + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// KeyProvider is responsible for providing key(s) to encrypt or decrypt a payload. +// Multiple `jwe.KeyProvider`s can be passed to `jwe.Encrypt()` or `jwe.Decrypt()` +// +// `jwe.Encrypt()` can only accept static key providers via `jwe.WithKey()`, +// while `jwe.Decrypt()` can accept `jwe.WithKey()`, `jwe.WithKeySet()`, +// and `jwe.WithKeyProvider()`. +// +// Understanding how this works is crucial to learn how this package works. +// Here we will use `jwe.Decrypt()` as an example to show how the `KeyProvider` +// works. +// +// `jwe.Encrypt()` is straightforward: the content encryption key is encrypted +// using the provided keys, and JWS recipient objects are created for each. +// +// `jwe.Decrypt()` is a bit more involved, because there are cases you +// will want to compute/deduce/guess the keys that you would like to +// use for decryption. +// +// The first thing that `jwe.Decrypt()` needs to do is to collect the +// KeyProviders from the option list that the user provided (presented in pseudocode): +// +// keyProviders := filterKeyProviders(options) +// +// Then, remember that a JWE message may contain multiple recipients in the +// message. For each recipient, we call on the KeyProviders to give us +// the key(s) to use on this CEK: +// +// for r in msg.Recipients { +// for kp in keyProviders { +// kp.FetchKeys(ctx, sink, r, msg) +// ... +// } +// } +// +// The `sink` argument passed to the KeyProvider is a temporary storage +// for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` +// is responsible for sending keys into the `sink`. +// +// When called, the `KeyProvider` created by `jwe.WithKey()` sends the same key, +// `jwe.WithKeySet()` sends keys that matches a particular `kid` and `alg`, +// and finally `jwe.WithKeyProvider()` allows you to execute arbitrary +// logic to provide keys. If you are providing a custom `KeyProvider`, +// you should execute the necessary checks or retrieval of keys, and +// then send the key(s) to the sink: +// +// sink.Key(alg, key) +// +// These keys are then retrieved and tried for each recipient, until +// a match is found: +// +// keys := sink.Keys() +// for key in keys { +// if decryptJWEKey(recipient.EncryptedKey(), key) { +// return OK +// } +// } +type KeyProvider interface { + FetchKeys(context.Context, KeySink, Recipient, *Message) error +} + +// KeySink is a data storage where `jwe.KeyProvider` objects should +// send their keys to. +type KeySink interface { + Key(jwa.KeyEncryptionAlgorithm, any) +} + +type algKeyPair struct { + alg jwa.KeyAlgorithm + key any +} + +type algKeySink struct { + mu sync.Mutex + list []algKeyPair +} + +func (s *algKeySink) Key(alg jwa.KeyEncryptionAlgorithm, key any) { + s.mu.Lock() + s.list = append(s.list, algKeyPair{alg, key}) + s.mu.Unlock() +} + +type staticKeyProvider struct { + alg jwa.KeyEncryptionAlgorithm + key any +} + +func (kp *staticKeyProvider) FetchKeys(_ context.Context, sink KeySink, _ Recipient, _ *Message) error { + sink.Key(kp.alg, kp.key) + return nil +} + +type keySetProvider struct { + set jwk.Set + requireKid bool +} + +func (kp *keySetProvider) selectKey(sink KeySink, key jwk.Key, _ Recipient, _ *Message) error { + if usage, ok := key.KeyUsage(); ok { + if usage != "" && usage != jwk.ForEncryption.String() { + return nil + } + } + + if v, ok := key.Algorithm(); ok { + kalg, ok := jwa.LookupKeyEncryptionAlgorithm(v.String()) + if !ok { + return fmt.Errorf(`invalid key encryption algorithm %s`, v) + } + + sink.Key(kalg, key) + return nil + } + + return nil +} + +func (kp *keySetProvider) FetchKeys(_ context.Context, sink KeySink, r Recipient, msg *Message) error { + if kp.requireKid { + var key jwk.Key + + wantedKid, ok := r.Headers().KeyID() + if !ok || wantedKid == "" { + return fmt.Errorf(`failed to find matching key: no key ID ("kid") specified in token but multiple keys available in key set`) + } + // Otherwise we better be able to look up the key, baby. + v, ok := kp.set.LookupKeyID(wantedKid) + if !ok { + return fmt.Errorf(`failed to find key with key ID %q in key set`, wantedKid) + } + key = v + + return kp.selectKey(sink, key, r, msg) + } + + for i := range kp.set.Len() { + key, _ := kp.set.Key(i) + if err := kp.selectKey(sink, key, r, msg); err != nil { + continue + } + } + return nil +} + +// KeyProviderFunc is a type of KeyProvider that is implemented by +// a single function. You can use this to create ad-hoc `KeyProvider` +// instances. +type KeyProviderFunc func(context.Context, KeySink, Recipient, *Message) error + +func (kp KeyProviderFunc) FetchKeys(ctx context.Context, sink KeySink, r Recipient, msg *Message) error { + return kp(ctx, sink, r, msg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/message.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/message.go new file mode 100644 index 0000000000..13cf3dec83 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/message.go @@ -0,0 +1,546 @@ +package jwe + +import ( + "fmt" + "sort" + "strings" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// NewRecipient creates a Recipient object +func NewRecipient() Recipient { + return &stdRecipient{ + headers: NewHeaders(), + } +} + +func (r *stdRecipient) SetHeaders(h Headers) error { + r.headers = h + return nil +} + +func (r *stdRecipient) SetEncryptedKey(v []byte) error { + r.encryptedKey = v + return nil +} + +func (r *stdRecipient) Headers() Headers { + return r.headers +} + +func (r *stdRecipient) EncryptedKey() []byte { + return r.encryptedKey +} + +type recipientMarshalProxy struct { + Headers Headers `json:"header"` + EncryptedKey string `json:"encrypted_key"` +} + +func (r *stdRecipient) UnmarshalJSON(buf []byte) error { + var proxy recipientMarshalProxy + proxy.Headers = NewHeaders() + if err := json.Unmarshal(buf, &proxy); err != nil { + return fmt.Errorf(`failed to unmarshal json into recipient: %w`, err) + } + + r.headers = proxy.Headers + decoded, err := base64.DecodeString(proxy.EncryptedKey) + if err != nil { + return fmt.Errorf(`failed to decode "encrypted_key": %w`, err) + } + r.encryptedKey = decoded + return nil +} + +func (r *stdRecipient) MarshalJSON() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(`{"header":`) + hdrbuf, err := json.Marshal(r.headers) + if err != nil { + return nil, fmt.Errorf(`failed to marshal recipient header: %w`, err) + } + buf.Write(hdrbuf) + buf.WriteString(`,"encrypted_key":"`) + buf.WriteString(base64.EncodeToString(r.encryptedKey)) + buf.WriteString(`"}`) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +// NewMessage creates a new message +func NewMessage() *Message { + return &Message{} +} + +func (m *Message) AuthenticatedData() []byte { + return m.authenticatedData +} + +func (m *Message) CipherText() []byte { + return m.cipherText +} + +func (m *Message) InitializationVector() []byte { + return m.initializationVector +} + +func (m *Message) Tag() []byte { + return m.tag +} + +func (m *Message) ProtectedHeaders() Headers { + return m.protectedHeaders +} + +func (m *Message) Recipients() []Recipient { + return m.recipients +} + +func (m *Message) UnprotectedHeaders() Headers { + return m.unprotectedHeaders +} + +const ( + AuthenticatedDataKey = "aad" + CipherTextKey = "ciphertext" + CountKey = "p2c" + InitializationVectorKey = "iv" + ProtectedHeadersKey = "protected" + RecipientsKey = "recipients" + SaltKey = "p2s" + TagKey = "tag" + UnprotectedHeadersKey = "unprotected" + HeadersKey = "header" + EncryptedKeyKey = "encrypted_key" +) + +func (m *Message) Set(k string, v any) error { + switch k { + case AuthenticatedDataKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, AuthenticatedDataKey) + } + m.authenticatedData = buf + case CipherTextKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, CipherTextKey) + } + m.cipherText = buf + case InitializationVectorKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, InitializationVectorKey) + } + m.initializationVector = buf + case ProtectedHeadersKey: + cv, ok := v.(Headers) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, ProtectedHeadersKey) + } + m.protectedHeaders = cv + case RecipientsKey: + cv, ok := v.([]Recipient) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, RecipientsKey) + } + m.recipients = cv + case TagKey: + buf, ok := v.([]byte) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, TagKey) + } + m.tag = buf + case UnprotectedHeadersKey: + cv, ok := v.(Headers) + if !ok { + return fmt.Errorf(`invalid value %T for %s key`, v, UnprotectedHeadersKey) + } + m.unprotectedHeaders = cv + default: + if m.unprotectedHeaders == nil { + m.unprotectedHeaders = NewHeaders() + } + return m.unprotectedHeaders.Set(k, v) + } + return nil +} + +type messageMarshalProxy struct { + AuthenticatedData string `json:"aad,omitempty"` + CipherText string `json:"ciphertext"` + InitializationVector string `json:"iv,omitempty"` + ProtectedHeaders json.RawMessage `json:"protected"` + Recipients []json.RawMessage `json:"recipients,omitempty"` + Tag string `json:"tag,omitempty"` + UnprotectedHeaders Headers `json:"unprotected,omitempty"` + + // For flattened structure. Headers is NOT a Headers type, + // so that we can detect its presence by checking proxy.Headers != nil + Headers json.RawMessage `json:"header,omitempty"` + EncryptedKey string `json:"encrypted_key,omitempty"` +} + +type jsonKV struct { + Key string + Value string +} + +func (m *Message) MarshalJSON() ([]byte, error) { + // This is slightly convoluted, but we need to encode the + // protected headers, so we do it by hand + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + + var fields []jsonKV + + if cipherText := m.CipherText(); len(cipherText) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(cipherText)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, CipherTextKey, err) + } + fields = append(fields, jsonKV{ + Key: CipherTextKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if iv := m.InitializationVector(); len(iv) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(iv)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, InitializationVectorKey, err) + } + fields = append(fields, jsonKV{ + Key: InitializationVectorKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + var encodedProtectedHeaders []byte + if h := m.ProtectedHeaders(); h != nil { + v, err := h.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to encode protected headers: %w`, err) + } + + encodedProtectedHeaders = v + if len(encodedProtectedHeaders) <= 2 { // '{}' + encodedProtectedHeaders = nil + } else { + fields = append(fields, jsonKV{ + Key: ProtectedHeadersKey, + Value: fmt.Sprintf("%q", encodedProtectedHeaders), + }) + } + } + + if aad := m.AuthenticatedData(); len(aad) > 0 { + aad = base64.Encode(aad) + if encodedProtectedHeaders != nil { + tmp := append(encodedProtectedHeaders, tokens.Period) + aad = append(tmp, aad...) + } + + buf.Reset() + if err := enc.Encode(aad); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, AuthenticatedDataKey, err) + } + fields = append(fields, jsonKV{ + Key: AuthenticatedDataKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if recipients := m.Recipients(); len(recipients) > 0 { + if len(recipients) == 1 { // Use flattened format + if hdrs := recipients[0].Headers(); hdrs != nil { + buf.Reset() + if err := enc.Encode(hdrs); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, HeadersKey, err) + } + fields = append(fields, jsonKV{ + Key: HeadersKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if ek := recipients[0].EncryptedKey(); len(ek) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(ek)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, EncryptedKeyKey, err) + } + fields = append(fields, jsonKV{ + Key: EncryptedKeyKey, + Value: strings.TrimSpace(buf.String()), + }) + } + } else { + buf.Reset() + if err := enc.Encode(recipients); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, RecipientsKey, err) + } + fields = append(fields, jsonKV{ + Key: RecipientsKey, + Value: strings.TrimSpace(buf.String()), + }) + } + } + + if tag := m.Tag(); len(tag) > 0 { + buf.Reset() + if err := enc.Encode(base64.EncodeToString(tag)); err != nil { + return nil, fmt.Errorf(`failed to encode %s field: %w`, TagKey, err) + } + fields = append(fields, jsonKV{ + Key: TagKey, + Value: strings.TrimSpace(buf.String()), + }) + } + + if h := m.UnprotectedHeaders(); h != nil { + unprotected, err := json.Marshal(h) + if err != nil { + return nil, fmt.Errorf(`failed to encode unprotected headers: %w`, err) + } + + if len(unprotected) > 2 { + fields = append(fields, jsonKV{ + Key: UnprotectedHeadersKey, + Value: fmt.Sprintf("%q", unprotected), + }) + } + } + + sort.Slice(fields, func(i, j int) bool { + return fields[i].Key < fields[j].Key + }) + buf.Reset() + fmt.Fprintf(buf, `{`) + for i, kv := range fields { + if i > 0 { + fmt.Fprintf(buf, `,`) + } + fmt.Fprintf(buf, `%q:%s`, kv.Key, kv.Value) + } + fmt.Fprintf(buf, `}`) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (m *Message) UnmarshalJSON(buf []byte) error { + var proxy messageMarshalProxy + proxy.UnprotectedHeaders = NewHeaders() + + if err := json.Unmarshal(buf, &proxy); err != nil { + return fmt.Errorf(`failed to unmashal JSON into message: %w`, err) + } + + // Get the string value + var protectedHeadersStr string + if err := json.Unmarshal(proxy.ProtectedHeaders, &protectedHeadersStr); err != nil { + return fmt.Errorf(`failed to decode protected headers (1): %w`, err) + } + + // It's now in _quoted_ base64 string. Decode it + protectedHeadersRaw, err := base64.DecodeString(protectedHeadersStr) + if err != nil { + return fmt.Errorf(`failed to base64 decoded protected headers buffer: %w`, err) + } + + h := NewHeaders() + if err := json.Unmarshal(protectedHeadersRaw, h); err != nil { + return fmt.Errorf(`failed to decode protected headers (2): %w`, err) + } + + // if this were a flattened message, we would see a "header" and "ciphertext" + // field. TODO: do both of these conditions need to meet, or just one? + if proxy.Headers != nil || len(proxy.EncryptedKey) > 0 { + recipient := NewRecipient() + hdrs := NewHeaders() + if err := json.Unmarshal(proxy.Headers, hdrs); err != nil { + return fmt.Errorf(`failed to decode headers field: %w`, err) + } + + if err := recipient.SetHeaders(hdrs); err != nil { + return fmt.Errorf(`failed to set new headers: %w`, err) + } + + if v := proxy.EncryptedKey; len(v) > 0 { + buf, err := base64.DecodeString(v) + if err != nil { + return fmt.Errorf(`failed to decode encrypted key: %w`, err) + } + if err := recipient.SetEncryptedKey(buf); err != nil { + return fmt.Errorf(`failed to set encrypted key: %w`, err) + } + } + + m.recipients = append(m.recipients, recipient) + } else { + for i, recipientbuf := range proxy.Recipients { + recipient := NewRecipient() + if err := json.Unmarshal(recipientbuf, recipient); err != nil { + return fmt.Errorf(`failed to decode recipient at index %d: %w`, i, err) + } + + m.recipients = append(m.recipients, recipient) + } + } + + if src := proxy.AuthenticatedData; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "aad": %w`, err) + } + m.authenticatedData = v + } + + if src := proxy.CipherText; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "ciphertext": %w`, err) + } + m.cipherText = v + } + + if src := proxy.InitializationVector; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "iv": %w`, err) + } + m.initializationVector = v + } + + if src := proxy.Tag; len(src) > 0 { + v, err := base64.DecodeString(src) + if err != nil { + return fmt.Errorf(`failed to decode "tag": %w`, err) + } + m.tag = v + } + + m.protectedHeaders = h + if m.storeProtectedHeaders { + // this is later used for decryption + m.rawProtectedHeaders = base64.Encode(protectedHeadersRaw) + } + + if iz, ok := proxy.UnprotectedHeaders.(isZeroer); ok { + if !iz.isZero() { + m.unprotectedHeaders = proxy.UnprotectedHeaders + } + } + + if len(m.recipients) == 0 { + if err := m.makeDummyRecipient(proxy.EncryptedKey, m.protectedHeaders); err != nil { + return fmt.Errorf(`failed to setup recipient: %w`, err) + } + } + + return nil +} + +func (m *Message) makeDummyRecipient(enckeybuf string, protected Headers) error { + // Recipients in this case should not contain the content encryption key, + // so move that out + hdrs, err := protected.Clone() + if err != nil { + return fmt.Errorf(`failed to clone headers: %w`, err) + } + + if err := hdrs.Remove(ContentEncryptionKey); err != nil { + return fmt.Errorf(`failed to remove %#v from public header: %w`, ContentEncryptionKey, err) + } + + enckey, err := base64.DecodeString(enckeybuf) + if err != nil { + return fmt.Errorf(`failed to decode encrypted key: %w`, err) + } + + if err := m.Set(RecipientsKey, []Recipient{ + &stdRecipient{ + headers: hdrs, + encryptedKey: enckey, + }, + }); err != nil { + return fmt.Errorf(`failed to set %s: %w`, RecipientsKey, err) + } + return nil +} + +// Compact generates a JWE message in compact serialization format from a +// `*jwe.Message` object. The object contain exactly one recipient, or +// an error is returned. +// +// This function currently does not take any options, but the function +// signature contains `options` for possible future expansion of the API +func Compact(m *Message, _ ...CompactOption) ([]byte, error) { + if len(m.recipients) != 1 { + return nil, fmt.Errorf(`wrong number of recipients for compact serialization`) + } + + recipient := m.recipients[0] + + // The protected header must be a merge between the message-wide + // protected header AND the recipient header + + // There's something wrong if m.protectedHeaders is nil, but + // it could happen + if m.protectedHeaders == nil { + return nil, fmt.Errorf(`invalid protected header`) + } + + hcopy, err := m.protectedHeaders.Clone() + if err != nil { + return nil, fmt.Errorf(`failed to copy protected header: %w`, err) + } + hcopy, err = hcopy.Merge(m.unprotectedHeaders) + if err != nil { + return nil, fmt.Errorf(`failed to merge unprotected header: %w`, err) + } + hcopy, err = hcopy.Merge(recipient.Headers()) + if err != nil { + return nil, fmt.Errorf(`failed to merge recipient header: %w`, err) + } + + protected, err := hcopy.Encode() + if err != nil { + return nil, fmt.Errorf(`failed to encode header: %w`, err) + } + + encryptedKey := base64.Encode(recipient.EncryptedKey()) + iv := base64.Encode(m.initializationVector) + cipher := base64.Encode(m.cipherText) + tag := base64.Encode(m.tag) + + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.Grow(len(protected) + len(encryptedKey) + len(iv) + len(cipher) + len(tag) + 4) + buf.Write(protected) + buf.WriteByte(tokens.Period) + buf.Write(encryptedKey) + buf.WriteByte(tokens.Period) + buf.Write(iv) + buf.WriteByte(tokens.Period) + buf.Write(cipher) + buf.WriteByte(tokens.Period) + buf.Write(tag) + + result := make([]byte, buf.Len()) + copy(result, buf.Bytes()) + return result, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.go new file mode 100644 index 0000000000..c9137eecf4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.go @@ -0,0 +1,108 @@ +package jwe + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/option/v2" +) + +// Specify contents of the protected header. Some fields such as +// "enc" and "zip" will be overwritten when encryption is performed. +// +// There is no equivalent for unprotected headers in this implementation +func WithProtectedHeaders(h Headers) EncryptOption { + cloned, _ := h.Clone() + return &encryptOption{option.New(identProtectedHeaders{}, cloned)} +} + +type withKey struct { + alg jwa.KeyAlgorithm + key any + headers Headers +} + +type WithKeySuboption interface { + Option + withKeySuboption() +} + +type withKeySuboption struct { + Option +} + +func (*withKeySuboption) withKeySuboption() {} + +// WithPerRecipientHeaders is used to pass header values for each recipient. +// Note that these headers are by definition _unprotected_. +func WithPerRecipientHeaders(hdr Headers) WithKeySuboption { + return &withKeySuboption{option.New(identPerRecipientHeaders{}, hdr)} +} + +// WithKey is used to pass a static algorithm/key pair to either `jwe.Encrypt()` or `jwe.Decrypt()`. +// either a raw key or `jwk.Key` may be passed as `key`. +// +// The `alg` parameter is the identifier for the key encryption algorithm that should be used. +// It is of type `jwa.KeyAlgorithm` but in reality you can only pass `jwa.KeyEncryptionAlgorithm` +// types. It is this way so that the value in `(jwk.Key).Algorithm()` can be directly +// passed to the option. If you specify other algorithm types such as `jwa.SignatureAlgorithm`, +// then you will get an error when `jwe.Encrypt()` or `jwe.Decrypt()` is executed. +// +// Unlike `jwe.WithKeySet()`, the `kid` field does not need to match for the key +// to be tried. +func WithKey(alg jwa.KeyAlgorithm, key any, options ...WithKeySuboption) EncryptDecryptOption { + var hdr Headers + for _, option := range options { + switch option.Ident() { + case identPerRecipientHeaders{}: + if err := option.Value(&hdr); err != nil { + panic(`jwe.WithKey() requires Headers value for WithPerRecipientHeaders option`) + } + } + } + + return &encryptDecryptOption{option.New(identKey{}, &withKey{ + alg: alg, + key: key, + headers: hdr, + })} +} + +func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) DecryptOption { + requireKid := true + for _, option := range options { + switch option.Ident() { + case identRequireKid{}: + if err := option.Value(&requireKid); err != nil { + panic(`jwe.WithKeySet() requires bool value for WithRequireKid option`) + } + } + } + + return WithKeyProvider(&keySetProvider{ + set: set, + requireKid: requireKid, + }) +} + +// WithJSON specifies that the result of `jwe.Encrypt()` is serialized in +// JSON format. +// +// If you pass multiple keys to `jwe.Encrypt()`, it will fail unless +// you also pass this option. +func WithJSON(options ...WithJSONSuboption) EncryptOption { + var pretty bool + for _, option := range options { + switch option.Ident() { + case identPretty{}: + if err := option.Value(&pretty); err != nil { + panic(`jwe.WithJSON() requires bool value for WithPretty option`) + } + } + } + + format := fmtJSON + if pretty { + format = fmtJSONPretty + } + return &encryptOption{option.New(identSerialization{}, format)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.yaml new file mode 100644 index 0000000000..b7fb0262de --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options.yaml @@ -0,0 +1,172 @@ +package_name: jwe +output: jwe/options_gen.go +interfaces: + - name: GlobalOption + comment: | + GlobalOption describes options that changes global settings for this package + - name: GlobalDecryptOption + comment: | + GlobalDecryptOption describes options that changes global settings and for each call of the `jwe.Decrypt` function + methods: + - globalOption + - decryptOption + - name: CompactOption + comment: | + CompactOption describes options that can be passed to `jwe.Compact` + - name: DecryptOption + comment: | + DecryptOption describes options that can be passed to `jwe.Decrypt` + - name: EncryptOption + comment: | + EncryptOption describes options that can be passed to `jwe.Encrypt` + - name: EncryptDecryptOption + methods: + - encryptOption + - decryptOption + comment: | + EncryptDecryptOption describes options that can be passed to either `jwe.Encrypt` or `jwe.Decrypt` + - name: WithJSONSuboption + concrete_type: withJSONSuboption + comment: | + JSONSuboption describes suboptions that can be passed to `jwe.WithJSON()` option + - name: WithKeySetSuboption + comment: | + WithKeySetSuboption is a suboption passed to the WithKeySet() option + - name: ParseOption + methods: + - readFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwe.ReadFile` +options: + - ident: Key + skip_option: true + - ident: Pretty + skip_option: true + - ident: ProtectedHeaders + skip_option: true + - ident: PerRecipientHeaders + skip_option: true + - ident: KeyProvider + interface: DecryptOption + argument_type: KeyProvider + - ident: Context + interface: DecryptOption + argument_type: context.Context + comment: | + WithContext specifies the context.Context object to use when decrypting a JWE message. + If not provided, context.Background() will be used. + - ident: Serialization + option_name: WithCompact + interface: EncryptOption + constant_value: fmtCompact + comment: | + WithCompact specifies that the result of `jwe.Encrypt()` is serialized in + compact format. + + By default `jwe.Encrypt()` will opt to use compact format, so you usually + do not need to specify this option other than to be explicit about it + - ident: Compress + interface: EncryptOption + argument_type: jwa.CompressionAlgorithm + comment: | + WithCompress specifies the compression algorithm to use when encrypting + a payload using `jwe.Encrypt` (Yes, we know it can only be "" or "DEF", + but the way the specification is written it could allow for more options, + and therefore this option takes an argument) + - ident: ContentEncryptionAlgorithm + interface: EncryptOption + option_name: WithContentEncryption + argument_type: jwa.ContentEncryptionAlgorithm + comment: | + WithContentEncryptionAlgorithm specifies the algorithm to encrypt the + JWE message content with. If not provided, `jwa.A256GCM` is used. + - ident: Message + interface: DecryptOption + argument_type: '*Message' + comment: | + WithMessage provides a message object to be populated by `jwe.Decrypt` + Using this option allows you to decrypt AND obtain the `jwe.Message` + in one go. + - ident: RequireKid + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithRequiredKid specifies whether the keys in the jwk.Set should + only be matched if the target JWE message's Key ID and the Key ID + in the given key matches. + - ident: Pretty + interface: WithJSONSuboption + argument_type: bool + comment: | + WithPretty specifies whether the JSON output should be formatted and + indented + - ident: MergeProtectedHeaders + interface: EncryptOption + argument_type: bool + comment: | + WithMergeProtectedHeaders specify that when given multiple headers + as options to `jwe.Encrypt`, these headers should be merged instead + of overwritten + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: KeyUsed + interface: DecryptOption + argument_type: 'any' + comment: | + WithKeyUsed allows you to specify the `jwe.Decrypt()` function to + return the key used for decryption. This may be useful when + you specify multiple key sources or if you pass a `jwk.Set` + and you want to know which key was successful at decrypting the + CEK. + + `v` must be a pointer to an empty `any`. Do not use + `jwk.Key` here unless you are 100% sure that all keys that you + have provided are instances of `jwk.Key` (remember that the + jwx API allows users to specify a raw key such as *rsa.PublicKey) + - ident: CEK + interface: DecryptOption + argument_type: '*[]byte' + comment: | + WithCEK allows users to specify a variable to store the CEK used in the + message upon successful decryption. The variable must be a pointer to + a byte slice, and it will only be populated if the decryption is successful. + + This option is currently considered EXPERIMENTAL, and is subject to + future changes across minor/micro versions. + - ident: MaxPBES2Count + interface: GlobalOption + argument_type: int + comment: | + WithMaxPBES2Count specifies the maximum number of PBES2 iterations + to use when decrypting a message. If not specified, the default + value of 10,000 is used. + + This option has a global effect. + - ident: MaxDecompressBufferSize + interface: GlobalDecryptOption + argument_type: int64 + comment: | + WithMaxDecompressBufferSize specifies the maximum buffer size for used when + decompressing the payload of a JWE message. If a compressed JWE payload + exceeds this amount when decompressed, jwe.Decrypt will return an error. + The default value is 10MB. + + This option can be used for `jwe.Settings()`, which changes the behavior + globally, or for `jwe.Decrypt()`, which changes the behavior for that + specific call. + - ident: CBCBufferSize + interface: GlobalOption + argument_type: int64 + comment: | + WithCBCBufferSize specifies the maximum buffer size for internal + calculations, such as when AES-CBC is performed. The default value is 256MB. + If set to an invalid value, the default value is used. + In v2, this option was called MaxBufferSize. + + This option has a global effect. \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwe/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options_gen.go new file mode 100644 index 0000000000..2a15c141b4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwe/options_gen.go @@ -0,0 +1,350 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwe + +import ( + "context" + "io/fs" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// CompactOption describes options that can be passed to `jwe.Compact` +type CompactOption interface { + Option + compactOption() +} + +type compactOption struct { + Option +} + +func (*compactOption) compactOption() {} + +// DecryptOption describes options that can be passed to `jwe.Decrypt` +type DecryptOption interface { + Option + decryptOption() +} + +type decryptOption struct { + Option +} + +func (*decryptOption) decryptOption() {} + +// EncryptDecryptOption describes options that can be passed to either `jwe.Encrypt` or `jwe.Decrypt` +type EncryptDecryptOption interface { + Option + encryptOption() + decryptOption() +} + +type encryptDecryptOption struct { + Option +} + +func (*encryptDecryptOption) encryptOption() {} + +func (*encryptDecryptOption) decryptOption() {} + +// EncryptOption describes options that can be passed to `jwe.Encrypt` +type EncryptOption interface { + Option + encryptOption() +} + +type encryptOption struct { + Option +} + +func (*encryptOption) encryptOption() {} + +// GlobalDecryptOption describes options that changes global settings and for each call of the `jwe.Decrypt` function +type GlobalDecryptOption interface { + Option + globalOption() + decryptOption() +} + +type globalDecryptOption struct { + Option +} + +func (*globalDecryptOption) globalOption() {} + +func (*globalDecryptOption) decryptOption() {} + +// GlobalOption describes options that changes global settings for this package +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` +type ParseOption interface { + Option + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwe.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// JSONSuboption describes suboptions that can be passed to `jwe.WithJSON()` option +type WithJSONSuboption interface { + Option + withJSONSuboption() +} + +type withJSONSuboption struct { + Option +} + +func (*withJSONSuboption) withJSONSuboption() {} + +// WithKeySetSuboption is a suboption passed to the WithKeySet() option +type WithKeySetSuboption interface { + Option + withKeySetSuboption() +} + +type withKeySetSuboption struct { + Option +} + +func (*withKeySetSuboption) withKeySetSuboption() {} + +type identCBCBufferSize struct{} +type identCEK struct{} +type identCompress struct{} +type identContentEncryptionAlgorithm struct{} +type identContext struct{} +type identFS struct{} +type identKey struct{} +type identKeyProvider struct{} +type identKeyUsed struct{} +type identMaxDecompressBufferSize struct{} +type identMaxPBES2Count struct{} +type identMergeProtectedHeaders struct{} +type identMessage struct{} +type identPerRecipientHeaders struct{} +type identPretty struct{} +type identProtectedHeaders struct{} +type identRequireKid struct{} +type identSerialization struct{} + +func (identCBCBufferSize) String() string { + return "WithCBCBufferSize" +} + +func (identCEK) String() string { + return "WithCEK" +} + +func (identCompress) String() string { + return "WithCompress" +} + +func (identContentEncryptionAlgorithm) String() string { + return "WithContentEncryption" +} + +func (identContext) String() string { + return "WithContext" +} + +func (identFS) String() string { + return "WithFS" +} + +func (identKey) String() string { + return "WithKey" +} + +func (identKeyProvider) String() string { + return "WithKeyProvider" +} + +func (identKeyUsed) String() string { + return "WithKeyUsed" +} + +func (identMaxDecompressBufferSize) String() string { + return "WithMaxDecompressBufferSize" +} + +func (identMaxPBES2Count) String() string { + return "WithMaxPBES2Count" +} + +func (identMergeProtectedHeaders) String() string { + return "WithMergeProtectedHeaders" +} + +func (identMessage) String() string { + return "WithMessage" +} + +func (identPerRecipientHeaders) String() string { + return "WithPerRecipientHeaders" +} + +func (identPretty) String() string { + return "WithPretty" +} + +func (identProtectedHeaders) String() string { + return "WithProtectedHeaders" +} + +func (identRequireKid) String() string { + return "WithRequireKid" +} + +func (identSerialization) String() string { + return "WithSerialization" +} + +// WithCBCBufferSize specifies the maximum buffer size for internal +// calculations, such as when AES-CBC is performed. The default value is 256MB. +// If set to an invalid value, the default value is used. +// In v2, this option was called MaxBufferSize. +// +// This option has a global effect. +func WithCBCBufferSize(v int64) GlobalOption { + return &globalOption{option.New(identCBCBufferSize{}, v)} +} + +// WithCEK allows users to specify a variable to store the CEK used in the +// message upon successful decryption. The variable must be a pointer to +// a byte slice, and it will only be populated if the decryption is successful. +// +// This option is currently considered EXPERIMENTAL, and is subject to +// future changes across minor/micro versions. +func WithCEK(v *[]byte) DecryptOption { + return &decryptOption{option.New(identCEK{}, v)} +} + +// WithCompress specifies the compression algorithm to use when encrypting +// a payload using `jwe.Encrypt` (Yes, we know it can only be "" or "DEF", +// but the way the specification is written it could allow for more options, +// and therefore this option takes an argument) +func WithCompress(v jwa.CompressionAlgorithm) EncryptOption { + return &encryptOption{option.New(identCompress{}, v)} +} + +// WithContentEncryptionAlgorithm specifies the algorithm to encrypt the +// JWE message content with. If not provided, `jwa.A256GCM` is used. +func WithContentEncryption(v jwa.ContentEncryptionAlgorithm) EncryptOption { + return &encryptOption{option.New(identContentEncryptionAlgorithm{}, v)} +} + +// WithContext specifies the context.Context object to use when decrypting a JWE message. +// If not provided, context.Background() will be used. +func WithContext(v context.Context) DecryptOption { + return &decryptOption{option.New(identContext{}, v)} +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +func WithKeyProvider(v KeyProvider) DecryptOption { + return &decryptOption{option.New(identKeyProvider{}, v)} +} + +// WithKeyUsed allows you to specify the `jwe.Decrypt()` function to +// return the key used for decryption. This may be useful when +// you specify multiple key sources or if you pass a `jwk.Set` +// and you want to know which key was successful at decrypting the +// CEK. +// +// `v` must be a pointer to an empty `any`. Do not use +// `jwk.Key` here unless you are 100% sure that all keys that you +// have provided are instances of `jwk.Key` (remember that the +// jwx API allows users to specify a raw key such as *rsa.PublicKey) +func WithKeyUsed(v any) DecryptOption { + return &decryptOption{option.New(identKeyUsed{}, v)} +} + +// WithMaxDecompressBufferSize specifies the maximum buffer size for used when +// decompressing the payload of a JWE message. If a compressed JWE payload +// exceeds this amount when decompressed, jwe.Decrypt will return an error. +// The default value is 10MB. +// +// This option can be used for `jwe.Settings()`, which changes the behavior +// globally, or for `jwe.Decrypt()`, which changes the behavior for that +// specific call. +func WithMaxDecompressBufferSize(v int64) GlobalDecryptOption { + return &globalDecryptOption{option.New(identMaxDecompressBufferSize{}, v)} +} + +// WithMaxPBES2Count specifies the maximum number of PBES2 iterations +// to use when decrypting a message. If not specified, the default +// value of 10,000 is used. +// +// This option has a global effect. +func WithMaxPBES2Count(v int) GlobalOption { + return &globalOption{option.New(identMaxPBES2Count{}, v)} +} + +// WithMergeProtectedHeaders specify that when given multiple headers +// as options to `jwe.Encrypt`, these headers should be merged instead +// of overwritten +func WithMergeProtectedHeaders(v bool) EncryptOption { + return &encryptOption{option.New(identMergeProtectedHeaders{}, v)} +} + +// WithMessage provides a message object to be populated by `jwe.Decrypt` +// Using this option allows you to decrypt AND obtain the `jwe.Message` +// in one go. +func WithMessage(v *Message) DecryptOption { + return &decryptOption{option.New(identMessage{}, v)} +} + +// WithPretty specifies whether the JSON output should be formatted and +// indented +func WithPretty(v bool) WithJSONSuboption { + return &withJSONSuboption{option.New(identPretty{}, v)} +} + +// WithRequiredKid specifies whether the keys in the jwk.Set should +// only be matched if the target JWE message's Key ID and the Key ID +// in the given key matches. +func WithRequireKid(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identRequireKid{}, v)} +} + +// WithCompact specifies that the result of `jwe.Encrypt()` is serialized in +// compact format. +// +// By default `jwe.Encrypt()` will opt to use compact format, so you usually +// do not need to specify this option other than to be explicit about it +func WithCompact() EncryptOption { + return &encryptOption{option.New(identSerialization{}, fmtCompact)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwk/BUILD.bazel new file mode 100644 index 0000000000..8e82e1f009 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/BUILD.bazel @@ -0,0 +1,87 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwk", + srcs = [ + "cache.go", + "convert.go", + "ecdsa.go", + "ecdsa_gen.go", + "errors.go", + "fetch.go", + "filter.go", + "interface.go", + "interface_gen.go", + "io.go", + "jwk.go", + "key_ops.go", + "okp.go", + "okp_gen.go", + "options.go", + "options_gen.go", + "parser.go", + "rsa.go", + "rsa_gen.go", + "set.go", + "symmetric.go", + "symmetric_gen.go", + "usage.go", + "whitelist.go", + "x509.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwk", + visibility = ["//visibility:public"], + deps = [ + "//cert", + "//internal/base64", + "//internal/ecutil", + "//transform", + "//internal/json", + "//internal/pool", + "//internal/tokens", + "//jwa", + "//jwk/ecdsa", + "//jwk/jwkbb", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwk_test", + srcs = [ + "filter_test.go", + "headers_test.go", + "jwk_internal_test.go", + "jwk_test.go", + "options_gen_test.go", + "refresh_test.go", + "set_test.go", + "x5c_test.go", + ], + data = glob(["testdata/**"]), + embed = [":jwk"], + deps = [ + "//cert", + "//internal/base64", + "//internal/jose", + "//internal/json", + "//internal/jwxtest", + "//internal/tokens", + "//jwa", + "//jwk/ecdsa", + "//jws", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_lestrrat_go_httprc_v3//tracesink", + "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwk", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwk/README.md new file mode 100644 index 0000000000..741dd4647d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/README.md @@ -0,0 +1,215 @@ +# JWK [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwk.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwk) + +Package jwk implements JWK as described in [RFC7517](https://tools.ietf.org/html/rfc7517). +If you are looking to use JWT wit JWKs, look no further than [github.com/lestrrat-go/jwx](../jwt). + +* Parse and work with RSA/EC/Symmetric/OKP JWK types + * Convert to and from JSON + * Convert to and from raw key types (e.g. *rsa.PrivateKey) +* Ability to keep a JWKS fresh using *jwk.AutoRefresh + +## Supported key types: + +| kty | Curve | Go Key Type | +|:----|:------------------------|:----------------------------------------------| +| RSA | N/A | rsa.PrivateKey / rsa.PublicKey (2) | +| EC | P-256
P-384
P-521
secp256k1 (1) | ecdsa.PrivateKey / ecdsa.PublicKey (2) | +| oct | N/A | []byte | +| OKP | Ed25519 (1) | ed25519.PrivateKey / ed25519.PublicKey (2) | +| | X25519 (1) | (jwx/)x25519.PrivateKey / x25519.PublicKey (2)| + +* Note 1: Experimental +* Note 2: Either value or pointers accepted (e.g. rsa.PrivateKey or *rsa.PrivateKey) + +# Documentation + +Please read the [API reference](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwk), or +the how-to style documentation on how to use JWK can be found in the [docs directory](../docs/04-jwk.md). + +# Auto-Refresh a key during a long-running process + + +```go +package examples_test + +import ( + "context" + "fmt" + "time" + + "github.com/lestrrat-go/httprc/v3" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +func Example_jwk_cache() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + const googleCerts = `https://www.googleapis.com/oauth2/v3/certs` + + // First, set up the `jwk.Cache` object. You need to pass it a + // `context.Context` object to control the lifecycle of the background fetching goroutine. + c, err := jwk.NewCache(ctx, httprc.NewClient()) + if err != nil { + fmt.Printf("failed to create cache: %s\n", err) + return + } + + // Tell *jwk.Cache that we only want to refresh this JWKS periodically. + if err := c.Register(ctx, googleCerts); err != nil { + fmt.Printf("failed to register google JWKS: %s\n", err) + return + } + + // Pretend that this is your program's main loop +MAIN: + for { + select { + case <-ctx.Done(): + break MAIN + default: + } + keyset, err := c.Lookup(ctx, googleCerts) + if err != nil { + fmt.Printf("failed to fetch google JWKS: %s\n", err) + return + } + _ = keyset + // The returned `keyset` will always be "reasonably" new. + // + // By "reasonably" we mean that we cannot guarantee that the keys will be refreshed + // immediately after it has been rotated in the remote source. But it should be close\ + // enough, and should you need to forcefully refresh the token using the `(jwk.Cache).Refresh()` method. + // + // If refetching the keyset fails, a cached version will be returned from the previous + // successful sync + + // Do interesting stuff with the keyset... but here, we just + // sleep for a bit + time.Sleep(time.Second) + + // Because we're a dummy program, we just cancel the loop now. + // If this were a real program, you presumably loop forever + cancel() + } + // OUTPUT: +} +``` +source: [examples/jwk_cache_example_test.go](https://github.com/lestrrat-go/jwx/blob/v3/examples/jwk_cache_example_test.go) + + +Parse and use a JWK key: + + +```go +package examples_test + +import ( + "context" + "fmt" + "log" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +func Example_jwk_usage() { + // Use jwk.Cache if you intend to keep reuse the JWKS over and over + set, err := jwk.Fetch(context.Background(), "https://www.googleapis.com/oauth2/v3/certs") + if err != nil { + log.Printf("failed to parse JWK: %s", err) + return + } + + // Key sets can be serialized back to JSON + { + jsonbuf, err := json.Marshal(set) + if err != nil { + log.Printf("failed to marshal key set into JSON: %s", err) + return + } + log.Printf("%s", jsonbuf) + } + + for i := 0; i < set.Len(); i++ { + var rawkey any // This is where we would like to store the raw key, like *rsa.PrivateKey or *ecdsa.PrivateKey + key, ok := set.Key(i) // This retrieves the corresponding jwk.Key + if !ok { + log.Printf("failed to get key at index %d", i) + return + } + + // jws and jwe operations can be performed using jwk.Key, but you could also + // covert it to their "raw" forms, such as *rsa.PrivateKey or *ecdsa.PrivateKey + if err := jwk.Export(key, &rawkey); err != nil { + log.Printf("failed to create public key: %s", err) + return + } + _ = rawkey + + // You can create jwk.Key from a raw key, too + fromRawKey, err := jwk.Import(rawkey) + if err != nil { + log.Printf("failed to acquire raw key from jwk.Key: %s", err) + return + } + + // Keys can be serialized back to JSON + jsonbuf, err := json.Marshal(key) + if err != nil { + log.Printf("failed to marshal key into JSON: %s", err) + return + } + + fromJSONKey, err := jwk.Parse(jsonbuf) + if err != nil { + log.Printf("failed to parse json: %s", err) + return + } + _ = fromJSONKey + _ = fromRawKey + } + // OUTPUT: +} + +//nolint:govet +func Example_jwk_marshal_json() { + // JWKs that inherently involve randomness such as RSA and EC keys are + // not used in this example, because they may produce different results + // depending on the environment. + // + // (In fact, even if you use a static source of randomness, tests may fail + // because of internal changes in the Go runtime). + + raw := []byte("01234567890123456789012345678901234567890123456789ABCDEF") + + // This would create a symmetric key + key, err := jwk.Import(raw) + if err != nil { + fmt.Printf("failed to create symmetric key: %s\n", err) + return + } + if _, ok := key.(jwk.SymmetricKey); !ok { + fmt.Printf("expected jwk.SymmetricKey, got %T\n", key) + return + } + + key.Set(jwk.KeyIDKey, "mykey") + + buf, err := json.MarshalIndent(key, "", " ") + if err != nil { + fmt.Printf("failed to marshal key into JSON: %s\n", err) + return + } + fmt.Printf("%s\n", buf) + + // OUTPUT: + // { + // "k": "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODlBQkNERUY", + // "kid": "mykey", + // "kty": "oct" + // } +} +``` +source: [examples/jwk_example_test.go](https://github.com/lestrrat-go/jwx/blob/v3/examples/jwk_example_test.go) + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/cache.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/cache.go new file mode 100644 index 0000000000..d827668e10 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/cache.go @@ -0,0 +1,358 @@ +package jwk + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/lestrrat-go/httprc/v3" +) + +type HTTPClient = httprc.HTTPClient +type ErrorSink = httprc.ErrorSink +type TraceSink = httprc.TraceSink + +// Cache is a container built on top of github.com/lestrrat-go/httprc/v3 +// that keeps track of Set object by their source URLs. +// The Set objects are stored in memory, and are refreshed automatically +// behind the scenes. +// +// Before retrieving the Set objects, the user must pre-register the +// URLs they intend to use by calling `Register()` +// +// c := jwk.NewCache(ctx, httprc.NewClient()) +// c.Register(ctx, url, options...) +// +// Once registered, you can call `Get()` to retrieve the Set object. +// +// All JWKS objects that are retrieved via this mechanism should be +// treated read-only, as they are shared among all consumers, as well +// as the `jwk.Cache` object. +// +// There are cases where `jwk.Cache` and `jwk.CachedSet` should and +// should not be used. +// +// First and foremost, do NOT use a cache for those JWKS objects that +// need constant checking. For example, unreliable or user-provided JWKS (i.e. those +// JWKS that are not from a well-known provider) should not be fetched +// through a `jwk.Cache` or `jwk.CachedSet`. +// +// For example, if you have a flaky JWKS server for development +// that can go down often, you should consider alternatives such as +// providing `http.Client` with a caching `http.RoundTripper` configured +// (see `jwk.WithHTTPClient`), setting up a reverse proxy, etc. +// These techniques allow you to set up a more robust way to both cache +// and report precise causes of the problems than using `jwk.Cache` or +// `jwk.CachedSet`. If you handle the caching at the HTTP level like this, +// you will be able to use a simple `jwk.Fetch` call and not worry about the cache. +// +// User-provided JWKS objects may also be problematic, as it may go down +// unexpectedly (and frequently!), and it will be hard to detect when +// the URLs or its contents are swapped. +// +// A good use-case for `jwk.Cache` and `jwk.CachedSet` are for "stable" +// JWKS objects. +// +// When we say "stable", we are thinking of JWKS that should mostly be +// ALWAYS available. A good example are those JWKS objects provided by +// major cloud providers such as Google Cloud, AWS, or Azure. +// Stable JWKS may still experience intermittent network connectivity problems, +// but you can expect that they will eventually recover in relatively +// short period of time. They rarely change URLs, and the contents are +// expected to be valid or otherwise it would cause havoc to those providers +// +// We also know that these stable JWKS objects are rotated periodically, +// which is a perfect use for `jwk.Cache` and `jwk.CachedSet`. The caches +// can be configured to periodically refresh the JWKS thereby keeping them +// fresh without extra intervention from the developer. +// +// Notice that for these recommended use-cases the requirement to check +// the validity or the availability of the JWKS objects are non-existent, +// as it is expected that they will be available and will be valid. The +// caching mechanism can hide intermittent connectivity problems as well +// as keep the objects mostly fresh. +type Cache struct { + ctrl httprc.Controller +} + +// Transformer is a specialized version of `httprc.Transformer` that implements +// conversion from a `http.Response` object to a `jwk.Set` object. Use this in +// conjection with `httprc.NewResource` to create a `httprc.Resource` object +// to auto-update `jwk.Set` objects. +type Transformer struct { + parseOptions []ParseOption +} + +func (t Transformer) Transform(_ context.Context, res *http.Response) (Set, error) { + buf, err := io.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf(`failed to read response body status: %w`, err) + } + + set, err := Parse(buf, t.parseOptions...) + if err != nil { + return nil, fmt.Errorf(`failed to parse JWK set at %q: %w`, res.Request.URL.String(), err) + } + + return set, nil +} + +// NewCache creates a new `jwk.Cache` object. +// +// Under the hood, `jwk.Cache` uses `httprc.Client` manage the +// fetching and caching of JWKS objects, and thus spawns multiple goroutines +// per `jwk.Cache` object. +// +// The provided `httprc.Client` object must NOT be started prior to +// passing it to `jwk.NewCache`. The `jwk.Cache` object will start +// the `httprc.Client` object on its own. +func NewCache(ctx context.Context, client *httprc.Client) (*Cache, error) { + ctrl, err := client.Start(ctx) + if err != nil { + return nil, fmt.Errorf(`failed to start httprc.Client: %w`, err) + } + + return &Cache{ + ctrl: ctrl, + }, nil +} + +// Register registers a URL to be managed by the cache. URLs must +// be registered before issuing `Get` +// +// The `Register` method is a thin wrapper around `(httprc.Controller).Add` +func (c *Cache) Register(ctx context.Context, u string, options ...RegisterOption) error { + var parseOptions []ParseOption + var resourceOptions []httprc.NewResourceOption + waitReady := true + for _, option := range options { + switch option := option.(type) { + case ParseOption: + parseOptions = append(parseOptions, option) + case ResourceOption: + var v httprc.NewResourceOption + if err := option.Value(&v); err != nil { + return fmt.Errorf(`failed to retrieve NewResourceOption option value: %w`, err) + } + resourceOptions = append(resourceOptions, v) + default: + switch option.Ident() { + case identHTTPClient{}: + var cli HTTPClient + if err := option.Value(&cli); err != nil { + return fmt.Errorf(`failed to retrieve HTTPClient option value: %w`, err) + } + resourceOptions = append(resourceOptions, httprc.WithHTTPClient(cli)) + case identWaitReady{}: + if err := option.Value(&waitReady); err != nil { + return fmt.Errorf(`failed to retrieve WaitReady option value: %w`, err) + } + } + } + } + + r, err := httprc.NewResource[Set](u, &Transformer{ + parseOptions: parseOptions, + }, resourceOptions...) + if err != nil { + return fmt.Errorf(`failed to create httprc.Resource: %w`, err) + } + if err := c.ctrl.Add(ctx, r, httprc.WithWaitReady(waitReady)); err != nil { + return fmt.Errorf(`failed to add resource to httprc.Client: %w`, err) + } + + return nil +} + +// LookupResource returns the `httprc.Resource` object associated with the +// given URL `u`. If the URL has not been registered, an error is returned. +func (c *Cache) LookupResource(ctx context.Context, u string) (*httprc.ResourceBase[Set], error) { + r, err := c.ctrl.Lookup(ctx, u) + if err != nil { + return nil, fmt.Errorf(`failed to lookup resource %q: %w`, u, err) + } + //nolint:forcetypeassert + return r.(*httprc.ResourceBase[Set]), nil +} + +func (c *Cache) Lookup(ctx context.Context, u string) (Set, error) { + r, err := c.LookupResource(ctx, u) + if err != nil { + return nil, fmt.Errorf(`failed to lookup resource %q: %w`, u, err) + } + set := r.Resource() + if set == nil { + return nil, fmt.Errorf(`resource %q is not ready`, u) + } + return set, nil +} + +func (c *Cache) Ready(ctx context.Context, u string) bool { + r, err := c.LookupResource(ctx, u) + if err != nil { + return false + } + if err := r.Ready(ctx); err != nil { + return false + } + return true +} + +// Refresh is identical to Get(), except it always fetches the +// specified resource anew, and updates the cached content +// +// Please refer to the documentation for `(httprc.Cache).Refresh` for +// more details +func (c *Cache) Refresh(ctx context.Context, u string) (Set, error) { + if err := c.ctrl.Refresh(ctx, u); err != nil { + return nil, fmt.Errorf(`failed to refresh resource %q: %w`, u, err) + } + return c.Lookup(ctx, u) +} + +// IsRegistered returns true if the given URL `u` has already been registered +// in the cache. +func (c *Cache) IsRegistered(ctx context.Context, u string) bool { + _, err := c.LookupResource(ctx, u) + return err == nil +} + +// Unregister removes the given URL `u` from the cache. +func (c *Cache) Unregister(ctx context.Context, u string) error { + return c.ctrl.Remove(ctx, u) +} + +// CachedSet is a thin shim over jwk.Cache that allows the user to cloak +// jwk.Cache as if it's a `jwk.Set`. Behind the scenes, the `jwk.Set` is +// retrieved from the `jwk.Cache` for every operation. +// +// Since `jwk.CachedSet` always deals with a cached version of the `jwk.Set`, +// all operations that mutate the object (such as AddKey(), RemoveKey(), et. al) +// are no-ops and return an error. +// +// Note that since this is a utility shim over `jwk.Cache`, you _will_ lose +// the ability to control the finer details (such as controlling how long to +// wait for in case of a fetch failure using `context.Context`) +// +// Make sure that you read the documentation for `jwk.Cache` as well. +type CachedSet interface { + Set + cached() (Set, error) // used as a marker +} + +type cachedSet struct { + r *httprc.ResourceBase[Set] +} + +func (c *Cache) CachedSet(u string) (CachedSet, error) { + r, err := c.LookupResource(context.Background(), u) + if err != nil { + return nil, fmt.Errorf(`failed to lookup resource %q: %w`, u, err) + } + return NewCachedSet(r), nil +} + +func NewCachedSet(r *httprc.ResourceBase[Set]) CachedSet { + return &cachedSet{ + r: r, + } +} + +func (cs *cachedSet) cached() (Set, error) { + if err := cs.r.Ready(context.Background()); err != nil { + return nil, fmt.Errorf(`failed to fetch resource: %w`, err) + } + return cs.r.Resource(), nil +} + +// Add is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) AddKey(_ Key) error { + return fmt.Errorf(`(jwk.Cachedset).AddKey: jwk.CachedSet is immutable`) +} + +// Clear is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) Clear() error { + return fmt.Errorf(`(jwk.cachedSet).Clear: jwk.CachedSet is immutable`) +} + +// Set is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) Set(_ string, _ any) error { + return fmt.Errorf(`(jwk.cachedSet).Set: jwk.CachedSet is immutable`) +} + +// Remove is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) Remove(_ string) error { + // TODO: Remove() should be renamed to Remove(string) error + return fmt.Errorf(`(jwk.cachedSet).Remove: jwk.CachedSet is immutable`) +} + +// RemoveKey is a no-op for `jwk.CachedSet`, as the `jwk.Set` should be treated read-only +func (*cachedSet) RemoveKey(_ Key) error { + return fmt.Errorf(`(jwk.cachedSet).RemoveKey: jwk.CachedSet is immutable`) +} + +func (cs *cachedSet) Clone() (Set, error) { + set, err := cs.cached() + if err != nil { + return nil, fmt.Errorf(`failed to get cached jwk.Set: %w`, err) + } + + return set.Clone() +} + +// Get returns the value of non-Key field stored in the jwk.Set +func (cs *cachedSet) Get(name string, dst any) error { + set, err := cs.cached() + if err != nil { + return err + } + + return set.Get(name, dst) +} + +// Key returns the Key at the specified index +func (cs *cachedSet) Key(idx int) (Key, bool) { + set, err := cs.cached() + if err != nil { + return nil, false + } + + return set.Key(idx) +} + +func (cs *cachedSet) Index(key Key) int { + set, err := cs.cached() + if err != nil { + return -1 + } + + return set.Index(key) +} + +func (cs *cachedSet) Keys() []string { + set, err := cs.cached() + if err != nil { + return nil + } + + return set.Keys() +} + +func (cs *cachedSet) Len() int { + set, err := cs.cached() + if err != nil { + return -1 + } + + return set.Len() +} + +func (cs *cachedSet) LookupKeyID(kid string) (Key, bool) { + set, err := cs.cached() + if err != nil { + return nil, false + } + + return set.LookupKeyID(kid) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/convert.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/convert.go new file mode 100644 index 0000000000..057f4b02a0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/convert.go @@ -0,0 +1,399 @@ +package jwk + +import ( + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "errors" + "fmt" + "math/big" + "reflect" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// # Converting between Raw Keys and `jwk.Key`s +// +// A converter that converts from a raw key to a `jwk.Key` is called a KeyImporter. +// A converter that converts from a `jwk.Key` to a raw key is called a KeyExporter. + +var keyImporters = make(map[reflect.Type]KeyImporter) +var keyExporters = make(map[jwa.KeyType][]KeyExporter) + +var muKeyImporters sync.RWMutex +var muKeyExporters sync.RWMutex + +// RegisterKeyImporter registers a KeyImporter for the given raw key. When `jwk.Import()` is called, +// the library will look up the appropriate KeyImporter for the given raw key type (via `reflect`) +// and execute the KeyImporters in succession until either one of them succeeds, or all of them fail. +func RegisterKeyImporter(from any, conv KeyImporter) { + muKeyImporters.Lock() + defer muKeyImporters.Unlock() + keyImporters[reflect.TypeOf(from)] = conv +} + +// RegisterKeyExporter registers a KeyExporter for the given key type. When `key.Raw()` is called, +// the library will look up the appropriate KeyExporter for the given key type and execute the +// KeyExporters in succession until either one of them succeeds, or all of them fail. +func RegisterKeyExporter(kty jwa.KeyType, conv KeyExporter) { + muKeyExporters.Lock() + defer muKeyExporters.Unlock() + convs, ok := keyExporters[kty] + if !ok { + convs = []KeyExporter{conv} + } else { + convs = append([]KeyExporter{conv}, convs...) + } + keyExporters[kty] = convs +} + +// KeyImporter is used to convert from a raw key to a `jwk.Key`. mneumonic: from the PoV of the `jwk.Key`, +// we're _importing_ a raw key. +type KeyImporter interface { + // Import takes the raw key to be converted, and returns a `jwk.Key` or an error if the conversion fails. + Import(any) (Key, error) +} + +// KeyImportFunc is a convenience type to implement KeyImporter as a function. +type KeyImportFunc func(any) (Key, error) + +func (f KeyImportFunc) Import(raw any) (Key, error) { + return f(raw) +} + +// KeyExporter is used to convert from a `jwk.Key` to a raw key. mneumonic: from the PoV of the `jwk.Key`, +// we're _exporting_ it to a raw key. +type KeyExporter interface { + // Export takes the `jwk.Key` to be converted, and a hint (the raw key to be converted to). + // The hint is the object that the user requested the result to be assigned to. + // The method should return the converted raw key, or an error if the conversion fails. + // + // Third party modules MUST NOT modifiy the hint object. + // + // When the user calls `key.Export(dst)`, the `dst` object is a _pointer_ to the + // object that the user wants the result to be assigned to, but the converter + // receives the _value_ that this pointer points to, to make it easier to + // detect the type of the result. + // + // Note that the second argument may be an `any` (which means that the + // user has delegated the type detection to the converter). + // + // Export must NOT modify the hint object, and should return jwk.ContinueError + // if the hint object is not compatible with the converter. + Export(Key, any) (any, error) +} + +// KeyExportFunc is a convenience type to implement KeyExporter as a function. +type KeyExportFunc func(Key, any) (any, error) + +func (f KeyExportFunc) Export(key Key, hint any) (any, error) { + return f(key, hint) +} + +func init() { + { + f := KeyImportFunc(rsaPrivateKeyToJWK) + k := rsa.PrivateKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(rsaPublicKeyToJWK) + k := rsa.PublicKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(ecdsaPrivateKeyToJWK) + k := ecdsa.PrivateKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(ecdsaPublicKeyToJWK) + k := ecdsa.PublicKey{} + RegisterKeyImporter(k, f) + RegisterKeyImporter(&k, f) + } + { + f := KeyImportFunc(okpPrivateKeyToJWK) + for _, k := range []any{ed25519.PrivateKey(nil)} { + RegisterKeyImporter(k, f) + } + } + { + f := KeyImportFunc(ecdhPrivateKeyToJWK) + for _, k := range []any{ecdh.PrivateKey{}, &ecdh.PrivateKey{}} { + RegisterKeyImporter(k, f) + } + } + { + f := KeyImportFunc(okpPublicKeyToJWK) + for _, k := range []any{ed25519.PublicKey(nil)} { + RegisterKeyImporter(k, f) + } + } + { + f := KeyImportFunc(ecdhPublicKeyToJWK) + for _, k := range []any{ecdh.PublicKey{}, &ecdh.PublicKey{}} { + RegisterKeyImporter(k, f) + } + } + RegisterKeyImporter([]byte(nil), KeyImportFunc(bytesToKey)) +} + +func ecdhPrivateKeyToJWK(src any) (Key, error) { + var raw *ecdh.PrivateKey + switch src := src.(type) { + case *ecdh.PrivateKey: + raw = src + case ecdh.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDH jwk.Key`, src) + } + + switch raw.Curve() { + case ecdh.X25519(): + return okpPrivateKeyToJWK(raw) + case ecdh.P256(): + return ecdhPrivateKeyToECJWK(raw, elliptic.P256()) + case ecdh.P384(): + return ecdhPrivateKeyToECJWK(raw, elliptic.P384()) + case ecdh.P521(): + return ecdhPrivateKeyToECJWK(raw, elliptic.P521()) + default: + return nil, fmt.Errorf(`unsupported curve %s`, raw.Curve()) + } +} + +func ecdhPrivateKeyToECJWK(raw *ecdh.PrivateKey, crv elliptic.Curve) (Key, error) { + pub := raw.PublicKey() + rawpub := pub.Bytes() + + size := ecutil.CalculateKeySize(crv) + var x, y, d big.Int + x.SetBytes(rawpub[1 : 1+size]) + y.SetBytes(rawpub[1+size:]) + d.SetBytes(raw.Bytes()) + + var ecdsaPriv ecdsa.PrivateKey + ecdsaPriv.Curve = crv + ecdsaPriv.D = &d + ecdsaPriv.X = &x + ecdsaPriv.Y = &y + return ecdsaPrivateKeyToJWK(&ecdsaPriv) +} + +func ecdhPublicKeyToJWK(src any) (Key, error) { + var raw *ecdh.PublicKey + switch src := src.(type) { + case *ecdh.PublicKey: + raw = src + case ecdh.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDH jwk.Key`, src) + } + + switch raw.Curve() { + case ecdh.X25519(): + return okpPublicKeyToJWK(raw) + case ecdh.P256(): + return ecdhPublicKeyToECJWK(raw, elliptic.P256()) + case ecdh.P384(): + return ecdhPublicKeyToECJWK(raw, elliptic.P384()) + case ecdh.P521(): + return ecdhPublicKeyToECJWK(raw, elliptic.P521()) + default: + return nil, fmt.Errorf(`unsupported curve %s`, raw.Curve()) + } +} + +func ecdhPublicKeyToECJWK(raw *ecdh.PublicKey, crv elliptic.Curve) (Key, error) { + rawbytes := raw.Bytes() + size := ecutil.CalculateKeySize(crv) + var x, y big.Int + + x.SetBytes(rawbytes[1 : 1+size]) + y.SetBytes(rawbytes[1+size:]) + var ecdsaPriv ecdsa.PublicKey + ecdsaPriv.Curve = crv + ecdsaPriv.X = &x + ecdsaPriv.Y = &y + return ecdsaPublicKeyToJWK(&ecdsaPriv) +} + +// These may seem a bit repetitive and redandunt, but the problem is that +// each key type has its own Import method -- for example, Import(*ecdsa.PrivateKey) +// vs Import(*rsa.PrivateKey), and therefore they can't just be bundled into +// a single function. +func rsaPrivateKeyToJWK(src any) (Key, error) { + var raw *rsa.PrivateKey + switch src := src.(type) { + case *rsa.PrivateKey: + raw = src + case rsa.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to RSA jwk.Key`, src) + } + k := newRSAPrivateKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func rsaPublicKeyToJWK(src any) (Key, error) { + var raw *rsa.PublicKey + switch src := src.(type) { + case *rsa.PublicKey: + raw = src + case rsa.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to RSA jwk.Key`, src) + } + k := newRSAPublicKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func ecdsaPrivateKeyToJWK(src any) (Key, error) { + var raw *ecdsa.PrivateKey + switch src := src.(type) { + case *ecdsa.PrivateKey: + raw = src + case ecdsa.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDSA jwk.Key`, src) + } + k := newECDSAPrivateKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func ecdsaPublicKeyToJWK(src any) (Key, error) { + var raw *ecdsa.PublicKey + switch src := src.(type) { + case *ecdsa.PublicKey: + raw = src + case ecdsa.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to ECDSA jwk.Key`, src) + } + k := newECDSAPublicKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func okpPrivateKeyToJWK(src any) (Key, error) { + var raw any + switch src.(type) { + case ed25519.PrivateKey, *ecdh.PrivateKey: + raw = src + case ecdh.PrivateKey: + raw = &src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to OKP jwk.Key`, src) + } + k := newOKPPrivateKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func okpPublicKeyToJWK(src any) (Key, error) { + var raw any + switch src.(type) { + case ed25519.PublicKey, *ecdh.PublicKey: + raw = src + case ecdh.PublicKey: + raw = &src + default: + return nil, fmt.Errorf(`jwk: convert raw to OKP jwk.Key: cannot convert key type '%T' to OKP jwk.Key`, src) + } + k := newOKPPublicKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +func bytesToKey(src any) (Key, error) { + var raw []byte + switch src := src.(type) { + case []byte: + raw = src + default: + return nil, fmt.Errorf(`cannot convert key type '%T' to symmetric jwk.Key`, src) + } + + k := newSymmetricKey() + if err := k.Import(raw); err != nil { + return nil, fmt.Errorf(`failed to initialize %T from %T: %w`, k, raw, err) + } + return k, nil +} + +// Export converts a `jwk.Key` to a Export key. The dst argument must be a pointer to the +// object that the user wants the result to be assigned to. +// +// Normally you would pass a pointer to the zero value of the raw key type +// such as &(*rsa.PrivateKey) or &(*ecdsa.PublicKey), which gets assigned +// the converted key. +// +// If you do not know the exact type of a jwk.Key before attempting +// to obtain the raw key, you can simply pass a pointer to an +// empty interface as the second argument +// +// If you already know the exact type, it is recommended that you +// pass a pointer to the zero value of the actual key type for efficiency. +// +// Be careful when/if you are using a third party key type that implements +// the `jwk.Key` interface, as the first argument. This function tries hard +// to Do The Right Thing, but it is not guaranteed to work in all cases, +// especially when the object implements the `jwk.Key` interface via +// embedding. +func Export(key Key, dst any) error { + // dst better be a pointer + rv := reflect.ValueOf(dst) + if rv.Kind() != reflect.Ptr { + return fmt.Errorf(`jwk.Export: destination object must be a pointer`) + } + muKeyExporters.RLock() + exporters, ok := keyExporters[key.KeyType()] + muKeyExporters.RUnlock() + if !ok { + return fmt.Errorf(`jwk.Export: no exporters registered for key type '%T'`, key) + } + for _, conv := range exporters { + v, err := conv.Export(key, dst) + if err != nil { + if errors.Is(err, ContinueError()) { + continue + } + return fmt.Errorf(`jwk.Export: failed to export jwk.Key to raw format: %w`, err) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`jwk.Export: failed to assign key: %w`, err) + } + return nil + } + return fmt.Errorf(`jwk.Export: no suitable exporter found for key type '%T'`, key) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/doc.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/doc.go new file mode 100644 index 0000000000..7df707521b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/doc.go @@ -0,0 +1,294 @@ +// Package jwk implements JWK as described in https://tools.ietf.org/html/rfc7517 +// +// This package implements jwk.Key to represent a single JWK, and jwk.Set to represent +// a set of JWKs. +// +// The `jwk.Key` type is an interface, which hides the underlying implementation for +// each key type. Each key type can further be converted to interfaces for known +// types, such as `jwk.ECDSAPrivateKey`, `jwk.RSAPublicKey`, etc. This may not necessarily +// work for third party key types (see section on "Registering a key type" below). +// +// Users can create a JWK in two ways. One is to unmarshal a JSON representation of a +// key. The second one is to use `jwk.Import()` to import a raw key and convert it to +// a jwk.Key. +// +// # Simple Usage +// +// You can parse a JWK from a JSON payload: +// +// jwk.ParseKey([]byte(`{"kty":"EC",...}`)) +// +// You can go back and forth between raw key types and JWKs: +// +// jwkKey, _ := jwk.Import(rsaPrivateKey) +// var rawKey *rsa.PRrivateKey +// jwkKey.Raw(&rawKey) +// +// You can use them to sign/verify/encrypt/decrypt: +// +// jws.Sign([]byte(`...`), jws.WithKey(jwa.RS256, jwkKey)) +// jwe.Encrypt([]byte(`...`), jwe.WithKey(jwa.RSA_OAEP, jwkKey)) +// +// See examples/jwk_parse_example_test.go and other files in the exmaples/ directory for more. +// +// # Advanced Usage: Registering a custom key type and conversion routines +// +// Caveat Emptor: Functionality around registering keys +// (KeyProbe/KeyParser/KeyImporter/KeyExporter) should be considered experimental. +// While we expect that the functionality itself will remain, the API may +// change in backward incompatible ways, even during minor version +// releases. +// +// ## tl;dr +// +// * KeyProbe: Used for parsing JWKs in JSON format. Probes hint fields to be used for later parsing by KeyParser +// * KeyParser: Used for parsing JWKs in JSON format. Parses the JSON payload into a jwk.Key using the KeyProbe as hint +// * KeyImporter: Used for converting raw key into jwk.Key. +// * KeyExporter: Used for converting jwk.Key into raw key. +// +// ## Overview +// +// You can add the ability to use a JWK type that this library does not +// implement out of the box. You can do this by registering your own +// KeyParser, KeyImporter, and KeyExporter instances. +// +// func init() { +// jwk.RegiserProbeField(reflect.StructField{Name: "SomeHint", Type: reflect.TypeOf(""), Tag: `json:"some_hint"`}) +// jwk.RegisterKeyParser(&MyKeyParser{}) +// jwk.RegisterKeyImporter(&MyKeyImporter{}) +// jwk.RegisterKeyExporter(&MyKeyExporter{}) +// } +// +// The KeyParser is used to parse JSON payloads and conver them into a jwk.Key. +// The KeyImporter is used to convert a raw key (e.g. *rsa.PrivateKey, *ecdsa.PrivateKey, etc) into a jwk.Key. +// The KeyExporter is used to convert a jwk.Key into a raw key. +// +// Although we believe the mechanism has been streamline quite a lot, it is also true +// that the entire process of parsing and converting keys are much more convoluted than you might +// think. Please know before hand that if you intend to add support for a new key type, +// it _WILL_ require you to learn this module pretty much in-and-out. +// +// Read on for more explanation. +// +// ## Registering a KeyParser +// +// In order to understand how parsing works, we need to explain how the `jwk.ParseKey()` works. +// +// The first thing that occurs when parsing a key is a partial +// unmarshaling of the payload into a hint / probe object. +// +// Because the `json.Unmarshal` works by calling the `UnmarshalJSON` +// method on a concrete object, we need to create a concrete object first. +// In order/ to create the appropriate Go object, we need to know which concrete +// object to create from the JSON payload, meaning we need to peek into the +// payload and figure out what type of key it is. +// +// In order to do this, we effectively need to parse the JSON payload twice. +// First, we "probe" the payload to figure out what kind of key it is, then +// we parse it again to create the actual key object. +// +// For probing, we create a new "probe" object (KeyProbe, which is not +// directly available to end users) to populate the object with hints from the payload. +// For example, a JWK representing an RSA key would look like: +// +// { "kty": "RSA", "n": ..., "e": ..., ... } +// +// The default KeyProbe is constructed to unmarshal "kty" and "d" fields, +// because that is enough information to determine what kind of key to +// construct. +// +// For example, if the payload contains "kty" field with the value "RSA", +// we know that it's an RSA key. If it contains "EC", we know that it's +// an EC key. Furthermore, if the payload contains some value in the "d" field, we can +// also tell that this is a private key, as only private keys need +// this field. +// +// For most cases, the default KeyProbe implementation should be sufficient. +// However, there may be cases in the future where there are new key types +// that require further information. Perhaps you are embedding another hint +// in your JWK to further specify what kind of key it is. In that case, you +// would need to probe more. +// +// Normally you can only change how an object is unmarshaled by specifying +// JSON tags when defining a struct, but we use `reflect` package capabilities +// to create an object dynamically, which is shared among all parsing operations. +// +// To add a new field to be probed, you need to register a new `reflect.StructField` +// object that has all of the information. For example, the code below would +// register a field named "MyHint" that is of type string, and has a JSON tag +// of "my_hint". +// +// jwk.RegisterProbeField(reflect.StructField{Name: "MyHint", Type: reflect.TypeOf(""), Tag: `json:"my_hint"`}) +// +// The value of this field can be retrieved by calling `Get()` method on the +// KeyProbe object (from the `KeyParser`'s `ParseKey()` method discussed later) +// +// var myhint string +// _ = probe.Get("MyHint", &myhint) +// +// var kty string +// _ = probe.Get("Kty", &kty) +// +// This mechanism allows you to be flexible when trying to determine the key type +// to instantiate. +// +// ## Parse via the KeyParser +// +// When `jwk.Parse` / `jwk.ParseKey` is called, the library will first probe +// the payload as discussed above. +// +// Once the probe is done, the library will iterate over the registered parsers +// and attempt to parse the key by calling their `ParseKey()` methods. +// +// The parsers will be called in reverse order that they were registered. +// This means that it will try all parsers that were registered by third +// parties, and once those are exhausted, the default parser will be used. +// +// Each parser's `ParseKey()“ method will receive three arguments: the probe object, a +// KeyUnmarshaler, and the raw payload. The probe object can be used +// as a hint to determine what kind of key to instantiate. An example +// pseudocode may look like this: +// +// var kty string +// _ = probe.Get("Kty", &kty) +// switch kty { +// case "RSA": +// // create an RSA key +// case "EC": +// // create an EC key +// ... +// } +// +// The `KeyUnmarshaler` is a thin wrapper around `json.Unmarshal`. It works almost +// identical to `json.Unmarshal`, but it allows us to add extra magic that is +// specific to this library (which users do not need to be aware of) before calling +// the actual `json.Unmarshal`. Please use the `KeyUnmarshaler` to unmarshal JWKs instead of `json.Unmarshal`. +// +// Putting it all together, the boiler plate for registering a new parser may look like this: +// +// func init() { +// jwk.RegisterFieldProbe(reflect.StructField{Name: "MyHint", Type: reflect.TypeOf(""), Tag: `json:"my_hint"`}) +// jwk.RegisterParser(&MyKeyParser{}) +// } +// +// type MyKeyParser struct { ... } +// func(*MyKeyParser) ParseKey(rawProbe *KeyProbe, unmarshaler KeyUnmarshaler, data []byte) (jwk.Key, error) { +// // Create concrete type +// var hint string +// if err := probe.Get("MyHint", &hint); err != nil { +// // if it doesn't have the `my_hint` field, it probably means +// // it's not for us, so we return ContinueParseError so that +// // the next parser can pick it up +// return nil, jwk.ContinueParseError() +// } +// +// // Use hint to determine concrete key type +// var key jwk.Key +// switch hint { +// case ...: +// key = = myNewAwesomeJWK() +// ... +// } +// +// return unmarshaler.Unmarshal(data, key) +// } +// +// ## Registering KeyImporter/KeyExporter +// +// If you are going to do anything with the key that was parsed by your KeyParser, +// you will need to tell the library how to convert back and forth between +// raw keys and JWKs. Conversion from raw keys to jwk.Keys are done by KeyImporters, +// and conversion from jwk.Keys to raw keys are done by KeyExporters. +// +// ## Using jwk.Import() using KeyImporter +// +// Each KeyImporter is hooked to run against a specific raw key type. +// +// When `jwk.Import()` is called, the library will iterate over all registered +// KeyImporters for the specified raw key type, and attempt to convert the raw +// key to a JWK by calling the `Import()` method on each KeyImporter. +// +// The KeyImporter's `Import()` method will receive the raw key to be converted, +// and should return a JWK or an error if the conversion fails, or the return +// `jwk.ContinueError()` if the specified raw key cannot be handled by ths/ KeyImporter. +// +// Once a KeyImporter is available, you will be able to pass the raw key to `jwk.Import()`. +// The following example shows how you might register a KeyImporter for a hypotheical +// mypkg.SuperSecretKey: +// +// jwk.RegisterKeyImporter(&mypkg.SuperSecretKey{}, jwk.KeyImportFunc(imnportSuperSecretKey)) +// +// func importSuperSecretKey(key any) (jwk.Key, error) { +// mykey, ok := key.(*mypkg.SuperSecretKey) +// if !ok { +// // You must return jwk.ContinueError here, or otherwise +// // processing will stop with an error +// return nil, fmt.Errorf("invalid key type %T for importer: %w", key, jwk.ContinueError()) +// } +// +// return mypkg.SuperSecretJWK{ .... }, nil // You could reuse existing JWK types if you can +// } +// +// ## Registering a KeyExporter +// +// KeyExporters are the opposite of KeyImporters: they convert a JWK to a raw key when `key.Raw(...)` is +// called. If you intend to use `key.Raw(...)` for a JWK created using one of your KeyImporters, +// you will also +// +// KeyExporters are registered by key type. For example, if you want to register a KeyExporter for +// RSA keys, you would do: +// +// jwk.RegisterKeyExporter(jwa.RSA, jwk.KeyExportFunc(exportRSAKey)) +// +// For a given JWK, it will be passed a "destination" object to store the exported raw key. For example, +// an RSA-based private JWK can be exported to a `*rsa.PrivateKey` or to a `*any`, but not +// to a `*ecdsa.PrivateKey`: +// +// var dst *rsa.PrivateKey +// key.Raw(&dst) // OK +// +// var dst any +// key.Raw(&dst) // OK +// +// var dst *ecdsa.PrivateKey +// key.Raw(&dst) // Error, if key is an RSA key +// +// You will need to handle this distinction yourself in your KeyImporter. For example, certain +// elliptic curve keys can be expressed in JWK in the same format, minus the "kty". In that case +// you will need to check for the type of the destination object and return an error if it is +// not compatible with your key. +// +// var raw mypkg.PrivateKey // assume a hypothetical private key type using a different curve than standard ones lie P-256 +// key, _ := jwk.Import(raw) +// // key could be jwk.ECDSAPrivateKey, with different curve than P-256 +// +// var dst *ecdsa.PrivateKey +// key.Raw(&dst) // your KeyImporter will be called with *ecdsa.PrivateKey, which is not compatible with your key +// +// To implement this your code should look like the following: +// +// jwk.RegisterKeyExporter(jwk.EC, jwk.KeyExportFunc(exportMyKey)) +// +// func exportMyKey(key jwk.Key, hint any) (any, error) { +// // check if the type of object in hint is compatible with your key +// switch hint.(type) { +// case *mypkg.PrivateKey, *any: +// // OK, we can proceed +// default: +// // Not compatible, return jwk.ContinueError +// return nil, jwk.ContinueError() +// } +// +// // key is a jwk.ECDSAPrivateKey or jwk.ECDSAPublicKey +// switch key := key.(type) { +// case jwk.ECDSAPrivateKey: +// // convert key to mypkg.PrivateKey +// case jwk.ECDSAPublicKey: +// // convert key to mypkg.PublicKey +// default: +// // Not compatible, return jwk.ContinueError +// return nil, jwk.ContinueError() +// } +// return ..., nil +// } +package jwk diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa.go new file mode 100644 index 0000000000..3dcd33bb1f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa.go @@ -0,0 +1,402 @@ +package jwk + +import ( + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/elliptic" + "fmt" + "math/big" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/jwa" + ourecdsa "github.com/lestrrat-go/jwx/v3/jwk/ecdsa" +) + +func init() { + ourecdsa.RegisterCurve(jwa.P256(), elliptic.P256()) + ourecdsa.RegisterCurve(jwa.P384(), elliptic.P384()) + ourecdsa.RegisterCurve(jwa.P521(), elliptic.P521()) + + RegisterKeyExporter(jwa.EC(), KeyExportFunc(ecdsaJWKToRaw)) +} + +func (k *ecdsaPublicKey) Import(rawKey *ecdsa.PublicKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + if rawKey.X == nil { + return fmt.Errorf(`invalid ecdsa.PublicKey`) + } + + if rawKey.Y == nil { + return fmt.Errorf(`invalid ecdsa.PublicKey`) + } + + xbuf := ecutil.AllocECPointBuffer(rawKey.X, rawKey.Curve) + ybuf := ecutil.AllocECPointBuffer(rawKey.Y, rawKey.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + + k.x = make([]byte, len(xbuf)) + copy(k.x, xbuf) + k.y = make([]byte, len(ybuf)) + copy(k.y, ybuf) + + alg, err := ourecdsa.AlgorithmFromCurve(rawKey.Curve) + if err != nil { + return fmt.Errorf(`jwk: failed to get algorithm for converting ECDSA public key to JWK: %w`, err) + } + k.crv = &alg + + return nil +} + +func (k *ecdsaPrivateKey) Import(rawKey *ecdsa.PrivateKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + if rawKey.PublicKey.X == nil { + return fmt.Errorf(`invalid ecdsa.PrivateKey`) + } + if rawKey.PublicKey.Y == nil { + return fmt.Errorf(`invalid ecdsa.PrivateKey`) + } + if rawKey.D == nil { + return fmt.Errorf(`invalid ecdsa.PrivateKey`) + } + + xbuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.X, rawKey.Curve) + ybuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.Y, rawKey.Curve) + dbuf := ecutil.AllocECPointBuffer(rawKey.D, rawKey.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + defer ecutil.ReleaseECPointBuffer(dbuf) + + k.x = make([]byte, len(xbuf)) + copy(k.x, xbuf) + k.y = make([]byte, len(ybuf)) + copy(k.y, ybuf) + k.d = make([]byte, len(dbuf)) + copy(k.d, dbuf) + + alg, err := ourecdsa.AlgorithmFromCurve(rawKey.Curve) + if err != nil { + return fmt.Errorf(`jwk: failed to get algorithm for converting ECDSA private key to JWK: %w`, err) + } + k.crv = &alg + + return nil +} + +func buildECDSAPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf, ybuf []byte) (*ecdsa.PublicKey, error) { + crv, err := ourecdsa.CurveFromAlgorithm(alg) + if err != nil { + return nil, fmt.Errorf(`jwk: failed to get algorithm for ECDSA public key: %w`, err) + } + + var x, y big.Int + x.SetBytes(xbuf) + y.SetBytes(ybuf) + + return &ecdsa.PublicKey{Curve: crv, X: &x, Y: &y}, nil +} + +func buildECDHPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf, ybuf []byte) (*ecdh.PublicKey, error) { + var ecdhcrv ecdh.Curve + switch alg { + case jwa.X25519(): + ecdhcrv = ecdh.X25519() + case jwa.P256(): + ecdhcrv = ecdh.P256() + case jwa.P384(): + ecdhcrv = ecdh.P384() + case jwa.P521(): + ecdhcrv = ecdh.P521() + default: + return nil, fmt.Errorf(`jwk: unsupported ECDH curve %s`, alg) + } + + return ecdhcrv.NewPublicKey(append([]byte{0x04}, append(xbuf, ybuf...)...)) +} + +func buildECDHPrivateKey(alg jwa.EllipticCurveAlgorithm, dbuf []byte) (*ecdh.PrivateKey, error) { + var ecdhcrv ecdh.Curve + switch alg { + case jwa.X25519(): + ecdhcrv = ecdh.X25519() + case jwa.P256(): + ecdhcrv = ecdh.P256() + case jwa.P384(): + ecdhcrv = ecdh.P384() + case jwa.P521(): + ecdhcrv = ecdh.P521() + default: + return nil, fmt.Errorf(`jwk: unsupported ECDH curve %s`, alg) + } + + return ecdhcrv.NewPrivateKey(dbuf) +} + +var ecdsaConvertibleTypes = []reflect.Type{ + reflect.TypeOf((*ECDSAPrivateKey)(nil)).Elem(), + reflect.TypeOf((*ECDSAPublicKey)(nil)).Elem(), +} + +func ecdsaJWKToRaw(keyif Key, hint any) (any, error) { + var isECDH bool + + extracted, err := extractEmbeddedKey(keyif, ecdsaConvertibleTypes) + if err != nil { + return nil, fmt.Errorf(`jwk: failed to extract embedded key: %w`, err) + } + + switch k := extracted.(type) { + case ECDSAPrivateKey: + switch hint.(type) { + case ecdsa.PrivateKey, *ecdsa.PrivateKey: + case ecdh.PrivateKey, *ecdh.PrivateKey: + isECDH = true + default: + rv := reflect.ValueOf(hint) + //nolint:revive + if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Interface { + // pointer to an interface value, presumably they want us to dynamically + // create an object of the right type + } else { + return nil, fmt.Errorf(`invalid destination object type %T: %w`, hint, ContinueError()) + } + } + + locker, ok := k.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + if isECDH { + d, ok := k.D() + if !ok { + return nil, fmt.Errorf(`missing "d" field`) + } + return buildECDHPrivateKey(crv, d) + } + + x, ok := k.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + y, ok := k.Y() + if !ok { + return nil, fmt.Errorf(`missing "y" field`) + } + pubk, err := buildECDSAPublicKey(crv, x, y) + if err != nil { + return nil, fmt.Errorf(`failed to build public key: %w`, err) + } + + var key ecdsa.PrivateKey + var d big.Int + + origD, ok := k.D() + if !ok { + return nil, fmt.Errorf(`missing "d" field`) + } + + d.SetBytes(origD) + key.D = &d + key.PublicKey = *pubk + + return &key, nil + case ECDSAPublicKey: + switch hint.(type) { + case ecdsa.PublicKey, *ecdsa.PublicKey: + case ecdh.PublicKey, *ecdh.PublicKey: + isECDH = true + default: + rv := reflect.ValueOf(hint) + //nolint:revive + if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Interface { + // pointer to an interface value, presumably they want us to dynamically + // create an object of the right type + } else { + return nil, fmt.Errorf(`invalid destination object type %T: %w`, hint, ContinueError()) + } + } + + locker, ok := k.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + x, ok := k.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + + y, ok := k.Y() + if !ok { + return nil, fmt.Errorf(`missing "y" field`) + } + if isECDH { + return buildECDHPublicKey(crv, x, y) + } + return buildECDSAPublicKey(crv, x, y) + default: + return nil, ContinueError() + } +} + +func makeECDSAPublicKey(src Key) (Key, error) { + newKey := newECDSAPublicKey() + + // Iterate and copy everything except for the bits that should not be in the public key + for _, k := range src.Keys() { + switch k { + case ECDSADKey: + continue + default: + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`ecdsa: makeECDSAPublicKey: failed to get field %q: %w`, k, err) + } + + if err := newKey.Set(k, v); err != nil { + return nil, fmt.Errorf(`ecdsa: makeECDSAPublicKey: failed to set field %q: %w`, k, err) + } + } + } + + return newKey, nil +} + +func (k *ecdsaPrivateKey) PublicKey() (Key, error) { + return makeECDSAPublicKey(k) +} + +func (k *ecdsaPublicKey) PublicKey() (Key, error) { + return makeECDSAPublicKey(k) +} + +func ecdsaThumbprint(hash crypto.Hash, crv, x, y string) []byte { + h := hash.New() + fmt.Fprint(h, `{"crv":"`) + fmt.Fprint(h, crv) + fmt.Fprint(h, `","kty":"EC","x":"`) + fmt.Fprint(h, x) + fmt.Fprint(h, `","y":"`) + fmt.Fprint(h, y) + fmt.Fprint(h, `"}`) + return h.Sum(nil) +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k ecdsaPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key ecdsa.PublicKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export ecdsa.PublicKey for thumbprint generation: %w`, err) + } + + xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve) + ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + + return ecdsaThumbprint( + hash, + key.Curve.Params().Name, + base64.EncodeToString(xbuf), + base64.EncodeToString(ybuf), + ), nil +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k ecdsaPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key ecdsa.PrivateKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export ecdsa.PrivateKey for thumbprint generation: %w`, err) + } + + xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve) + ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve) + defer ecutil.ReleaseECPointBuffer(xbuf) + defer ecutil.ReleaseECPointBuffer(ybuf) + + return ecdsaThumbprint( + hash, + key.Curve.Params().Name, + base64.EncodeToString(xbuf), + base64.EncodeToString(ybuf), + ), nil +} + +func ecdsaValidateKey(k interface { + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) + Y() ([]byte, bool) +}, checkPrivate bool) error { + crvtyp, ok := k.Crv() + if !ok { + return fmt.Errorf(`missing "crv" field`) + } + + crv, err := ourecdsa.CurveFromAlgorithm(crvtyp) + if err != nil { + return fmt.Errorf(`invalid curve algorithm %q: %w`, crvtyp, err) + } + + keySize := ecutil.CalculateKeySize(crv) + if x, ok := k.X(); !ok || len(x) != keySize { + return fmt.Errorf(`invalid "x" length (%d) for curve %q`, len(x), crv.Params().Name) + } + + if y, ok := k.Y(); !ok || len(y) != keySize { + return fmt.Errorf(`invalid "y" length (%d) for curve %q`, len(y), crv.Params().Name) + } + + if checkPrivate { + if priv, ok := k.(keyWithD); ok { + if d, ok := priv.D(); !ok || len(d) != keySize { + return fmt.Errorf(`invalid "d" length (%d) for curve %q`, len(d), crv.Params().Name) + } + } else { + return fmt.Errorf(`missing "d" value`) + } + } + return nil +} + +func (k *ecdsaPrivateKey) Validate() error { + if err := ecdsaValidateKey(k, true); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.ECDSAPrivateKey: %w`, err)) + } + return nil +} + +func (k *ecdsaPublicKey) Validate() error { + if err := ecdsaValidateKey(k, false); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.ECDSAPublicKey: %w`, err)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/BUILD.bazel new file mode 100644 index 0000000000..bf058aa649 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/BUILD.bazel @@ -0,0 +1,15 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "ecdsa", + srcs = ["ecdsa.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwk/ecdsa", + visibility = ["//visibility:public"], + deps = ["//jwa"], +) + +alias( + name = "go_default_library", + actual = ":ecdsa", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/ecdsa.go new file mode 100644 index 0000000000..3392483218 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa/ecdsa.go @@ -0,0 +1,76 @@ +package ecdsa + +import ( + "crypto/elliptic" + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" +) + +var muCurves sync.RWMutex +var algToCurveMap map[jwa.EllipticCurveAlgorithm]elliptic.Curve +var curveToAlgMap map[elliptic.Curve]jwa.EllipticCurveAlgorithm +var algList []jwa.EllipticCurveAlgorithm + +func init() { + muCurves.Lock() + algToCurveMap = make(map[jwa.EllipticCurveAlgorithm]elliptic.Curve) + curveToAlgMap = make(map[elliptic.Curve]jwa.EllipticCurveAlgorithm) + muCurves.Unlock() +} + +// RegisterCurve registers a jwa.EllipticCurveAlgorithm constant and its +// corresponding elliptic.Curve object. Users do not need to call this unless +// they are registering a new ECDSA key type +func RegisterCurve(alg jwa.EllipticCurveAlgorithm, crv elliptic.Curve) { + muCurves.Lock() + defer muCurves.Unlock() + + algToCurveMap[alg] = crv + curveToAlgMap[crv] = alg + rebuildCurves() +} + +func rebuildCurves() { + l := len(algToCurveMap) + if cap(algList) < l { + algList = make([]jwa.EllipticCurveAlgorithm, 0, l) + } else { + algList = algList[:0] + } + + for alg := range algToCurveMap { + algList = append(algList, alg) + } +} + +// Algorithms returns the list of registered jwa.EllipticCurveAlgorithms +// that ca be used for ECDSA keys. +func Algorithms() []jwa.EllipticCurveAlgorithm { + muCurves.RLock() + defer muCurves.RUnlock() + + return algList +} + +func AlgorithmFromCurve(crv elliptic.Curve) (jwa.EllipticCurveAlgorithm, error) { + alg, ok := curveToAlgMap[crv] + if !ok { + return jwa.InvalidEllipticCurve(), fmt.Errorf(`unknown elliptic curve: %q`, crv) + } + return alg, nil +} + +func CurveFromAlgorithm(alg jwa.EllipticCurveAlgorithm) (elliptic.Curve, error) { + crv, ok := algToCurveMap[alg] + if !ok { + return nil, fmt.Errorf(`unknown elliptic curve algorithm: %q`, alg) + } + return crv, nil +} + +func IsCurveAvailable(alg jwa.EllipticCurveAlgorithm) bool { + _, ok := algToCurveMap[alg] + return ok +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa_gen.go new file mode 100644 index 0000000000..39536de3d8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/ecdsa_gen.go @@ -0,0 +1,1432 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + ECDSACrvKey = "crv" + ECDSADKey = "d" + ECDSAXKey = "x" + ECDSAYKey = "y" +) + +type ECDSAPublicKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) + Y() ([]byte, bool) +} + +type ecdsaPublicKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + y []byte + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ ECDSAPublicKey = &ecdsaPublicKey{} +var _ Key = &ecdsaPublicKey{} + +func newECDSAPublicKey() *ecdsaPublicKey { + return &ecdsaPublicKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h ecdsaPublicKey) KeyType() jwa.KeyType { + return jwa.EC() +} + +func (h ecdsaPublicKey) rlock() { + h.mu.RLock() +} + +func (h ecdsaPublicKey) runlock() { + h.mu.RUnlock() +} + +func (h ecdsaPublicKey) IsPrivate() bool { + return false +} + +func (h *ecdsaPublicKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *ecdsaPublicKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *ecdsaPublicKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *ecdsaPublicKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *ecdsaPublicKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *ecdsaPublicKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *ecdsaPublicKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *ecdsaPublicKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *ecdsaPublicKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *ecdsaPublicKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *ecdsaPublicKey) Y() ([]byte, bool) { + if h.y != nil { + return h.y, true + } + return nil, false +} + +func (h *ecdsaPublicKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case ECDSACrvKey: + return h.crv != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case ECDSAXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + case ECDSAYKey: + return h.y != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *ecdsaPublicKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`ecdsaPublicKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSACrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAYKey: + if h.y == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.y); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *ecdsaPublicKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *ecdsaPublicKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case ECDSACrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSACrvKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case ECDSAXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + case ECDSAYKey: + if v, ok := value.([]byte); ok { + h.y = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAYKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *ecdsaPublicKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case ECDSACrvKey: + k.crv = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case ECDSAXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + case ECDSAYKey: + k.y = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *ecdsaPublicKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`ecdsaPublicKey.Clone: %w`, err) + } + return key, nil +} + +func (k *ecdsaPublicKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *ecdsaPublicKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *ecdsaPublicKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.y = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.EC().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case ECDSACrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSACrvKey, err) + } + h.crv = &decoded + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case ECDSAXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + case ECDSAYKey: + if err := json.AssignNextBytesToken(&h.y, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAYKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + if h.y == nil { + return fmt.Errorf(`required field y is missing`) + } + return nil +} + +func (h ecdsaPublicKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 11) + data[KeyTypeKey] = jwa.EC() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[ECDSACrvKey] = *(h.crv) + fields = append(fields, ECDSACrvKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[ECDSAXKey] = h.x + fields = append(fields, ECDSAXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + if h.y != nil { + data[ECDSAYKey] = h.y + fields = append(fields, ECDSAYKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *ecdsaPublicKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 11+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, ECDSACrvKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, ECDSAXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + if h.y != nil { + keys = append(keys, ECDSAYKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +type ECDSAPrivateKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + D() ([]byte, bool) + X() ([]byte, bool) + Y() ([]byte, bool) +} + +type ecdsaPrivateKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + d []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + y []byte + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ ECDSAPrivateKey = &ecdsaPrivateKey{} +var _ Key = &ecdsaPrivateKey{} + +func newECDSAPrivateKey() *ecdsaPrivateKey { + return &ecdsaPrivateKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h ecdsaPrivateKey) KeyType() jwa.KeyType { + return jwa.EC() +} + +func (h ecdsaPrivateKey) rlock() { + h.mu.RLock() +} + +func (h ecdsaPrivateKey) runlock() { + h.mu.RUnlock() +} + +func (h ecdsaPrivateKey) IsPrivate() bool { + return true +} + +func (h *ecdsaPrivateKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *ecdsaPrivateKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *ecdsaPrivateKey) D() ([]byte, bool) { + if h.d != nil { + return h.d, true + } + return nil, false +} + +func (h *ecdsaPrivateKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *ecdsaPrivateKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *ecdsaPrivateKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *ecdsaPrivateKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *ecdsaPrivateKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *ecdsaPrivateKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *ecdsaPrivateKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *ecdsaPrivateKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *ecdsaPrivateKey) Y() ([]byte, bool) { + if h.y != nil { + return h.y, true + } + return nil, false +} + +func (h *ecdsaPrivateKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case ECDSACrvKey: + return h.crv != nil + case ECDSADKey: + return h.d != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case ECDSAXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + case ECDSAYKey: + return h.y != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *ecdsaPrivateKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`ecdsaPrivateKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSACrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSADKey: + if h.d == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.d); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ECDSAYKey: + if h.y == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.y); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *ecdsaPrivateKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *ecdsaPrivateKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case ECDSACrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSACrvKey, value) + case ECDSADKey: + if v, ok := value.([]byte); ok { + h.d = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSADKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case ECDSAXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + case ECDSAYKey: + if v, ok := value.([]byte); ok { + h.y = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ECDSAYKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *ecdsaPrivateKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case ECDSACrvKey: + k.crv = nil + case ECDSADKey: + k.d = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case ECDSAXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + case ECDSAYKey: + k.y = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *ecdsaPrivateKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`ecdsaPrivateKey.Clone: %w`, err) + } + return key, nil +} + +func (k *ecdsaPrivateKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *ecdsaPrivateKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *ecdsaPrivateKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.d = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.y = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.EC().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case ECDSACrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSACrvKey, err) + } + h.crv = &decoded + case ECDSADKey: + if err := json.AssignNextBytesToken(&h.d, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSADKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case ECDSAXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + case ECDSAYKey: + if err := json.AssignNextBytesToken(&h.y, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ECDSAYKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.d == nil { + return fmt.Errorf(`required field d is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + if h.y == nil { + return fmt.Errorf(`required field y is missing`) + } + return nil +} + +func (h ecdsaPrivateKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 12) + data[KeyTypeKey] = jwa.EC() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[ECDSACrvKey] = *(h.crv) + fields = append(fields, ECDSACrvKey) + } + if h.d != nil { + data[ECDSADKey] = h.d + fields = append(fields, ECDSADKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[ECDSAXKey] = h.x + fields = append(fields, ECDSAXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + if h.y != nil { + data[ECDSAYKey] = h.y + fields = append(fields, ECDSAYKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *ecdsaPrivateKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 12+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, ECDSACrvKey) + } + if h.d != nil { + keys = append(keys, ECDSADKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, ECDSAXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + if h.y != nil { + keys = append(keys, ECDSAYKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var ecdsaStandardFields KeyFilter + +func init() { + ecdsaStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, ECDSACrvKey, ECDSAXKey, ECDSAYKey, ECDSADKey) +} + +// ECDSAStandardFieldsFilter returns a KeyFilter that filters out standard ECDSA fields. +func ECDSAStandardFieldsFilter() KeyFilter { + return ecdsaStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/errors.go new file mode 100644 index 0000000000..af7e00d952 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/errors.go @@ -0,0 +1,79 @@ +package jwk + +import ( + "errors" + "fmt" +) + +var cpe = &continueError{} + +// ContinueError returns an opaque error that can be returned +// when a `KeyParser`, `KeyImporter`, or `KeyExporter` cannot handle the given payload, +// but would like the process to continue with the next handler. +func ContinueError() error { + return cpe +} + +type continueError struct{} + +func (e *continueError) Error() string { + return "continue parsing" +} + +type importError struct { + error +} + +func (e importError) Unwrap() error { + return e.error +} + +func (importError) Is(err error) bool { + _, ok := err.(importError) + return ok +} + +func importerr(f string, args ...any) error { + return importError{fmt.Errorf(`jwk.Import: `+f, args...)} +} + +var errDefaultImportError = importError{errors.New(`import error`)} + +func ImportError() error { + return errDefaultImportError +} + +type parseError struct { + error +} + +func (e parseError) Unwrap() error { + return e.error +} + +func (parseError) Is(err error) bool { + _, ok := err.(parseError) + return ok +} + +func bparseerr(prefix string, f string, args ...any) error { + return parseError{fmt.Errorf(prefix+`: `+f, args...)} +} + +func parseerr(f string, args ...any) error { + return bparseerr(`jwk.Parse`, f, args...) +} + +func rparseerr(f string, args ...any) error { + return bparseerr(`jwk.ParseReader`, f, args...) +} + +func sparseerr(f string, args ...any) error { + return bparseerr(`jwk.ParseString`, f, args...) +} + +var errDefaultParseError = parseError{errors.New(`parse error`)} + +func ParseError() error { + return errDefaultParseError +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/es256k.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/es256k.go new file mode 100644 index 0000000000..48114bbaee --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/es256k.go @@ -0,0 +1,14 @@ +//go:build jwx_es256k +// +build jwx_es256k + +package jwk + +import ( + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/lestrrat-go/jwx/v3/jwa" + ourecdsa "github.com/lestrrat-go/jwx/v3/jwk/ecdsa" +) + +func init() { + ourecdsa.RegisterCurve(jwa.Secp256k1(), secp256k1.S256()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/fetch.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/fetch.go new file mode 100644 index 0000000000..2b7917fd21 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/fetch.go @@ -0,0 +1,117 @@ +package jwk + +import ( + "context" + "fmt" + "io" + "net/http" +) + +// Fetcher is an interface that represents an object that fetches a JWKS. +// Currently this is only used in the `jws.WithVerifyAuto` option. +// +// Particularly, do not confuse this as the backend to `jwk.Fetch()` function. +// If you need to control how `jwk.Fetch()` implements HTTP requests look into +// providing a custom `http.Client` object via `jwk.WithHTTPClient` option +type Fetcher interface { + Fetch(context.Context, string, ...FetchOption) (Set, error) +} + +// FetchFunc describes a type of Fetcher that is represented as a function. +// +// You can use this to wrap functions (e.g. `jwk.Fetch“) as a Fetcher object. +type FetchFunc func(context.Context, string, ...FetchOption) (Set, error) + +func (ff FetchFunc) Fetch(ctx context.Context, u string, options ...FetchOption) (Set, error) { + return ff(ctx, u, options...) +} + +// CachedFetcher wraps `jwk.Cache` so that it can be used as a `jwk.Fetcher`. +// +// One notable diffence from a general use fetcher is that `jwk.CachedFetcher` +// can only be used with JWKS URLs that have been registered with the cache. +// Please read the documentation fo `(jwk.CachedFetcher).Fetch` for more details. +// +// This object is intended to be used with `jws.WithVerifyAuto` option, specifically +// for a scenario where there is a very small number of JWKS URLs that are trusted +// and used to verify JWS messages. It is NOT meant to be used as a general purpose +// caching fetcher object. +type CachedFetcher struct { + cache *Cache +} + +// Creates a new `jwk.CachedFetcher` object. +func NewCachedFetcher(cache *Cache) *CachedFetcher { + return &CachedFetcher{cache} +} + +// Fetch fetches a JWKS from the cache. If the JWKS URL has not been registered with +// the cache, an error is returned. +func (f *CachedFetcher) Fetch(ctx context.Context, u string, _ ...FetchOption) (Set, error) { + if !f.cache.IsRegistered(ctx, u) { + return nil, fmt.Errorf(`jwk.CachedFetcher: url %q has not been registered`, u) + } + return f.cache.Lookup(ctx, u) +} + +// Fetch fetches a JWK resource specified by a URL. The url must be +// pointing to a resource that is supported by `net/http`. +// +// This function is just a wrapper around `net/http` and `jwk.Parse`. +// There is nothing special here, so you are safe to use your own +// mechanism to fetch the JWKS. +// +// If you are using the same `jwk.Set` for long periods of time during +// the lifecycle of your program, and would like to periodically refresh the +// contents of the object with the data at the remote resource, +// consider using `jwk.Cache`, which automatically refreshes +// jwk.Set objects asynchronously. +func Fetch(ctx context.Context, u string, options ...FetchOption) (Set, error) { + var parseOptions []ParseOption + //nolint:revive // I want to keep the type of `wl` as `Whitelist` instead of `InsecureWhitelist` + var wl Whitelist = InsecureWhitelist{} + var client HTTPClient = http.DefaultClient + for _, option := range options { + if parseOpt, ok := option.(ParseOption); ok { + parseOptions = append(parseOptions, parseOpt) + continue + } + + switch option.Ident() { + case identHTTPClient{}: + if err := option.Value(&client); err != nil { + return nil, fmt.Errorf(`failed to retrieve HTTPClient option value: %w`, err) + } + case identFetchWhitelist{}: + if err := option.Value(&wl); err != nil { + return nil, fmt.Errorf(`failed to retrieve fetch whitelist option value: %w`, err) + } + } + } + + if !wl.IsAllowed(u) { + return nil, fmt.Errorf(`jwk.Fetch: url %q has been rejected by whitelist`, u) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + return nil, fmt.Errorf(`jwk.Fetch: failed to create new request: %w`, err) + } + + res, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf(`jwk.Fetch: request failed: %w`, err) + } + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf(`jwk.Fetch: request returned status %d, expected 200`, res.StatusCode) + } + + buf, err := io.ReadAll(res.Body) + defer res.Body.Close() + if err != nil { + return nil, fmt.Errorf(`jwk.Fetch: failed to read response body for %q: %w`, u, err) + } + + return Parse(buf, parseOptions...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/filter.go new file mode 100644 index 0000000000..e73b0757da --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/filter.go @@ -0,0 +1,28 @@ +package jwk + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// KeyFilter is an interface that allows users to filter JWK key fields. +// It provides two methods: Filter and Reject; Filter returns a new key with only +// the fields that match the filter criteria, while Reject returns a new key with +// only the fields that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type KeyFilter interface { + Filter(key Key) (Key, error) + Reject(key Key) (Key, error) +} + +// NewFieldNameFilter creates a new FieldNameFilter with the specified field names. +// +// Note that because some JWK fields are associated with the type instead of +// stored as data, this filter will not be able to remove them. An example would +// be the `kty` field: it's associated with the underlying JWK key type, and will +// always be present even if you attempt to remove it. +func NewFieldNameFilter(names ...string) KeyFilter { + return transform.NewNameBasedFilter[Key](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface.go new file mode 100644 index 0000000000..c157c2362c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface.go @@ -0,0 +1,143 @@ +package jwk + +import ( + "sync" + + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +// AsymmetricKey describes a Key that represents a key in an asymmetric key pair, +// which in turn can be either a private or a public key. This interface +// allows those keys to be queried if they are one or the other. +type AsymmetricKey interface { + IsPrivate() bool +} + +// KeyUsageType is used to denote what this key should be used for +type KeyUsageType string + +const ( + // ForSignature is the value used in the headers to indicate that + // this key should be used for signatures + ForSignature KeyUsageType = "sig" + // ForEncryption is the value used in the headers to indicate that + // this key should be used for encrypting + ForEncryption KeyUsageType = "enc" +) + +type KeyOperation string +type KeyOperationList []KeyOperation + +const ( + KeyOpSign KeyOperation = "sign" // (compute digital signature or MAC) + KeyOpVerify KeyOperation = "verify" // (verify digital signature or MAC) + KeyOpEncrypt KeyOperation = "encrypt" // (encrypt content) + KeyOpDecrypt KeyOperation = "decrypt" // (decrypt content and validate decryption, if applicable) + KeyOpWrapKey KeyOperation = "wrapKey" // (encrypt key) + KeyOpUnwrapKey KeyOperation = "unwrapKey" // (decrypt key and validate decryption, if applicable) + KeyOpDeriveKey KeyOperation = "deriveKey" // (derive key) + KeyOpDeriveBits KeyOperation = "deriveBits" // (derive bits not to be used as a key) +) + +// Set represents JWKS object, a collection of jwk.Key objects. +// +// Sets can be safely converted to and from JSON using the standard +// `"encoding/json".Marshal` and `"encoding/json".Unmarshal`. However, +// if you do not know if the payload contains a single JWK or a JWK set, +// consider using `jwk.Parse()` to always get a `jwk.Set` out of it. +// +// Since v1.2.12, JWK sets with private parameters can be parsed as well. +// Such private parameters can be accessed via the `Field()` method. +// If a resource contains a single JWK instead of a JWK set, private parameters +// are stored in _both_ the resulting `jwk.Set` object and the `jwk.Key` object . +// +//nolint:interfacebloat +type Set interface { + // AddKey adds the specified key. If the key already exists in the set, + // an error is returned. + AddKey(Key) error + + // Clear resets the list of keys associated with this set, emptying the + // internal list of `jwk.Key`s, as well as clearing any other non-key + // fields + Clear() error + + // Get returns the key at index `idx`. If the index is out of range, + // then the second return value is false. + Key(int) (Key, bool) + + // Get returns the value of a private field in the key set. + // + // For the purposes of a key set, any field other than the "keys" field is + // considered to be a private field. In other words, you cannot use this + // method to directly access the list of keys in the set + Get(string, any) error + + // Set sets the value of a single field. + // + // This method, which takes an `any`, exists because + // these objects can contain extra _arbitrary_ fields that users can + // specify, and there is no way of knowing what type they could be. + Set(string, any) error + + // Remove removes the specified non-key field from the set. + // Keys may not be removed using this method. See RemoveKey for + // removing keys. + Remove(string) error + + // Index returns the index where the given key exists, -1 otherwise + Index(Key) int + + // Len returns the number of keys in the set + Len() int + + // LookupKeyID returns the first key matching the given key id. + // The second return value is false if there are no keys matching the key id. + // The set *may* contain multiple keys with the same key id. If you + // need all of them, use `Iterate()` + LookupKeyID(string) (Key, bool) + + // RemoveKey removes the key from the set. + // RemoveKey returns an error when the specified key does not exist + // in set. + RemoveKey(Key) error + + // Keys returns the list of keys present in the Set, except for `keys`. + // e.g. if you had `{"keys": ["a", "b"], "c": .., "d": ...}`, this method would + // return `["c", "d"]`. Note that the order of the keys is not guaranteed. + // + // TODO: name is confusing between this and Key() + Keys() []string + + // Clone create a new set with identical keys. Keys themselves are not cloned. + Clone() (Set, error) +} + +type set struct { + keys []Key + mu sync.RWMutex + dc DecodeCtx + privateParams map[string]any +} + +type PublicKeyer interface { + // PublicKey creates the corresponding PublicKey type for this object. + // All fields are copied onto the new public key, except for those that are not allowed. + // Returned value must not be the receiver itself. + PublicKey() (Key, error) +} + +type DecodeCtx interface { + json.DecodeCtx + IgnoreParseError() bool +} +type KeyWithDecodeCtx interface { + SetDecodeCtx(DecodeCtx) + DecodeCtx() DecodeCtx +} + +// Used internally: It's used to lock a key +type rlocker interface { + rlock() + runlock() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface_gen.go new file mode 100644 index 0000000000..4f23d96cb0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/interface_gen.go @@ -0,0 +1,109 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "crypto" + + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + KeyTypeKey = "kty" + KeyUsageKey = "use" + KeyOpsKey = "key_ops" + AlgorithmKey = "alg" + KeyIDKey = "kid" + X509URLKey = "x5u" + X509CertChainKey = "x5c" + X509CertThumbprintKey = "x5t" + X509CertThumbprintS256Key = "x5t#S256" +) + +// Key defines the minimal interface for each of the +// key types. Their use and implementation differ significantly +// between each key type, so you should use type assertions +// to perform more specific tasks with each key +type Key interface { + + // Has returns true if the specified field has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + + // Get is used to extract the value of any field, including non-standard fields, out of the key. + // + // The first argument is the name of the field. The second argument is a pointer + // to a variable that will receive the value of the field. The method returns + // an error if the field does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + Get(string, any) error + + // Set sets the value of a single field. Note that certain fields, + // notably "kty", cannot be altered, but will not return an error + // + // This method, which takes an `any`, exists because + // these objects can contain extra _arbitrary_ fields that users can + // specify, and there is no way of knowing what type they could be + Set(string, any) error + + // Remove removes the field associated with the specified key. + // There is no way to remove the `kty` (key type). You will ALWAYS be left with one field in a jwk.Key. + Remove(string) error + // Validate performs _minimal_ checks if the data stored in the key are valid. + // By minimal, we mean that it does not check if the key is valid for use in + // cryptographic operations. For example, it does not check if an RSA key's + // `e` field is a valid exponent, or if the `n` field is a valid modulus. + // Instead, it checks for things such as the _presence_ of some required fields, + // or if certain keys' values are of particular length. + // + // Note that depending on th underlying key type, use of this method requires + // that multiple fields in the key are properly populated. For example, an EC + // key's "x", "y" fields cannot be validated unless the "crv" field is populated first. + // + // Validate is never called by `UnmarshalJSON()` or `Set`. It must explicitly be + // called by the user + Validate() error + + // Thumbprint returns the JWK thumbprint using the indicated + // hashing algorithm, according to RFC 7638 + Thumbprint(crypto.Hash) ([]byte, error) + + // Keys returns a list of the keys contained in this jwk.Key. + Keys() []string + + // Clone creates a new instance of the same type + Clone() (Key, error) + + // PublicKey creates the corresponding PublicKey type for this object. + // All fields are copied onto the new public key, except for those that are not allowed. + // + // If the key is already a public key, it returns a new copy minus the disallowed fields as above. + PublicKey() (Key, error) + + // KeyType returns the `kty` of a JWK + KeyType() jwa.KeyType + // KeyUsage returns `use` of a JWK + KeyUsage() (string, bool) + // KeyOps returns `key_ops` of a JWK + KeyOps() (KeyOperationList, bool) + // Algorithm returns `alg` of a JWK + + // Algorithm returns the value of the `alg` field. + // + // This field may contain either `jwk.SignatureAlgorithm`, `jwk.KeyEncryptionAlgorithm`, or `jwk.ContentEncryptionAlgorithm`. + // This is why there exists a `jwa.KeyAlgorithm` type that encompasses both types. + Algorithm() (jwa.KeyAlgorithm, bool) + // KeyID returns `kid` of a JWK + KeyID() (string, bool) + // X509URL returns `x5u` of a JWK + X509URL() (string, bool) + // X509CertChain returns `x5c` of a JWK + X509CertChain() (*cert.Chain, bool) + // X509CertThumbprint returns `x5t` of a JWK + X509CertThumbprint() (string, bool) + // X509CertThumbprintS256 returns `x5t#S256` of a JWK + X509CertThumbprintS256() (string, bool) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/io.go new file mode 100644 index 0000000000..29b30274cc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/io.go @@ -0,0 +1,42 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jwk + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (Set, error) { + var parseOptions []ParseOption + for _, option := range options { + if po, ok := option.(ParseOption); ok { + parseOptions = append(parseOptions, po) + } + } + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f, parseOptions...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwk.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwk.go new file mode 100644 index 0000000000..785feaf94c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwk.go @@ -0,0 +1,709 @@ +//go:generate ../tools/cmd/genjwk.sh + +package jwk + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io" + "math/big" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +var registry = json.NewRegistry() + +func bigIntToBytes(n *big.Int) ([]byte, error) { + if n == nil { + return nil, fmt.Errorf(`invalid *big.Int value`) + } + return n.Bytes(), nil +} + +func init() { + if err := RegisterProbeField(reflect.StructField{ + Name: "Kty", + Type: reflect.TypeOf(""), + Tag: `json:"kty"`, + }); err != nil { + panic(fmt.Errorf("failed to register mandatory probe for 'kty' field: %w", err)) + } + if err := RegisterProbeField(reflect.StructField{ + Name: "D", + Type: reflect.TypeOf(json.RawMessage(nil)), + Tag: `json:"d,omitempty"`, + }); err != nil { + panic(fmt.Errorf("failed to register mandatory probe for 'kty' field: %w", err)) + } +} + +// Import creates a jwk.Key from the given key (RSA/ECDSA/symmetric keys). +// +// The constructor auto-detects the type of key to be instantiated +// based on the input type: +// +// - "crypto/rsa".PrivateKey and "crypto/rsa".PublicKey creates an RSA based key +// - "crypto/ecdsa".PrivateKey and "crypto/ecdsa".PublicKey creates an EC based key +// - "crypto/ed25519".PrivateKey and "crypto/ed25519".PublicKey creates an OKP based key +// - "crypto/ecdh".PrivateKey and "crypto/ecdh".PublicKey creates an OKP based key +// - []byte creates a symmetric key +func Import(raw any) (Key, error) { + if raw == nil { + return nil, importerr(`a non-nil key is required`) + } + + muKeyImporters.RLock() + conv, ok := keyImporters[reflect.TypeOf(raw)] + muKeyImporters.RUnlock() + if !ok { + return nil, importerr(`failed to convert %T to jwk.Key: no converters were able to convert`, raw) + } + + return conv.Import(raw) +} + +// PublicSetOf returns a new jwk.Set consisting of +// public keys of the keys contained in the set. +// +// This is useful when you are generating a set of private keys, and +// you want to generate the corresponding public versions for the +// users to verify with. +// +// Be aware that all fields will be copied onto the new public key. It is the caller's +// responsibility to remove any fields, if necessary. +func PublicSetOf(v Set) (Set, error) { + newSet := NewSet() + + n := v.Len() + for i := range n { + k, ok := v.Key(i) + if !ok { + return nil, fmt.Errorf(`key not found`) + } + pubKey, err := PublicKeyOf(k) + if err != nil { + return nil, fmt.Errorf(`failed to get public key of %T: %w`, k, err) + } + if err := newSet.AddKey(pubKey); err != nil { + return nil, fmt.Errorf(`failed to add key to public key set: %w`, err) + } + } + + return newSet, nil +} + +// PublicKeyOf returns the corresponding public version of the jwk.Key. +// If `v` is a SymmetricKey, then the same value is returned. +// If `v` is already a public key, the key itself is returned. +// +// If `v` is a private key type that has a `PublicKey()` method, be aware +// that all fields will be copied onto the new public key. It is the caller's +// responsibility to remove any fields, if necessary +// +// If `v` is a raw key, the key is first converted to a `jwk.Key` +func PublicKeyOf(v any) (Key, error) { + // This should catch all jwk.Key instances + if pk, ok := v.(PublicKeyer); ok { + return pk.PublicKey() + } + + jk, err := Import(v) + if err != nil { + return nil, fmt.Errorf(`jwk.PublicKeyOf: failed to convert key into JWK: %w`, err) + } + + return jk.PublicKey() +} + +// PublicRawKeyOf returns the corresponding public key of the given +// value `v` (e.g. given *rsa.PrivateKey, *rsa.PublicKey is returned) +// If `v` is already a public key, the key itself is returned. +// +// The returned value will always be a pointer to the public key, +// except when a []byte (e.g. symmetric key, ed25519 key) is passed to `v`. +// In this case, the same []byte value is returned. +// +// This function must go through converting the object once to a jwk.Key, +// then back to a raw key, so it's not exactly efficient. +func PublicRawKeyOf(v any) (any, error) { + pk, ok := v.(PublicKeyer) + if !ok { + k, err := Import(v) + if err != nil { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to convert key to jwk.Key: %w`, err) + } + + pk, ok = k.(PublicKeyer) + if !ok { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to convert key to jwk.PublicKeyer: %w`, err) + } + } + + pubk, err := pk.PublicKey() + if err != nil { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to obtain public key from %T: %w`, v, err) + } + + var raw any + if err := Export(pubk, &raw); err != nil { + return nil, fmt.Errorf(`jwk.PublicRawKeyOf: failed to obtain raw key from %T: %w`, pubk, err) + } + return raw, nil +} + +// ParseRawKey is a combination of ParseKey and Raw. It parses a single JWK key, +// and assigns the "raw" key to the given parameter. The key must either be +// a pointer to an empty interface, or a pointer to the actual raw key type +// such as *rsa.PrivateKey, *ecdsa.PublicKey, *[]byte, etc. +func ParseRawKey(data []byte, rawkey any) error { + key, err := ParseKey(data) + if err != nil { + return fmt.Errorf(`failed to parse key: %w`, err) + } + + if err := Export(key, rawkey); err != nil { + return fmt.Errorf(`failed to assign to raw key variable: %w`, err) + } + + return nil +} + +type setDecodeCtx struct { + json.DecodeCtx + + ignoreParseError bool +} + +func (ctx *setDecodeCtx) IgnoreParseError() bool { + return ctx.ignoreParseError +} + +// ParseKey parses a single key JWK. Unlike `jwk.Parse` this method will +// report failure if you attempt to pass a JWK set. Only use this function +// when you know that the data is a single JWK. +// +// Given a WithPEM(true) option, this function assumes that the given input +// is PEM encoded ASN.1 DER format key. +// +// Note that a successful parsing of any type of key does NOT necessarily +// guarantee a valid key. For example, no checks against expiration dates +// are performed for certificate expiration, no checks against missing +// parameters are performed, etc. +func ParseKey(data []byte, options ...ParseOption) (Key, error) { + var parsePEM bool + var localReg *json.Registry + var pemDecoder PEMDecoder + for _, option := range options { + switch option.Ident() { + case identPEM{}: + if err := option.Value(&parsePEM); err != nil { + return nil, fmt.Errorf(`failed to retrieve PEM option value: %w`, err) + } + case identPEMDecoder{}: + if err := option.Value(&pemDecoder); err != nil { + return nil, fmt.Errorf(`failed to retrieve PEMDecoder option value: %w`, err) + } + case identLocalRegistry{}: + if err := option.Value(&localReg); err != nil { + return nil, fmt.Errorf(`failed to retrieve local registry option value: %w`, err) + } + case identTypedField{}: + var pair typedFieldPair // temporary var needed for typed field + if err := option.Value(&pair); err != nil { + return nil, fmt.Errorf(`failed to retrieve typed field option value: %w`, err) + } + if localReg == nil { + localReg = json.NewRegistry() + } + localReg.Register(pair.Name, pair.Value) + case identIgnoreParseError{}: + return nil, fmt.Errorf(`jwk.WithIgnoreParseError() cannot be used for ParseKey()`) + } + } + + if parsePEM { + var raw any + + // PEMDecoder should probably be deprecated, because of being a misnomer. + if pemDecoder != nil { + if err := decodeX509WithPEMDEcoder(&raw, data, pemDecoder); err != nil { + return nil, fmt.Errorf(`failed to decode PEM encoded key: %w`, err) + } + } else { + // This version takes into account the various X509 decoders that are + // pre-registered. + if err := decodeX509(&raw, data); err != nil { + return nil, fmt.Errorf(`failed to decode X.509 encoded key: %w`, err) + } + } + return Import(raw) + } + + probe, err := keyProbe.Probe(data) + if err != nil { + return nil, fmt.Errorf(`jwk.Parse: failed to probe data: %w`, err) + } + + unmarshaler := keyUnmarshaler{localReg: localReg} + + muKeyParser.RLock() + parsers := make([]KeyParser, len(keyParsers)) + copy(parsers, keyParsers) + muKeyParser.RUnlock() + + for i := len(parsers) - 1; i >= 0; i-- { + parser := parsers[i] + key, err := parser.ParseKey(probe, &unmarshaler, data) + if err == nil { + return key, nil + } + + if errors.Is(err, ContinueError()) { + continue + } + + return nil, err + } + return nil, fmt.Errorf(`jwk.Parse: no parser was able to parse the key`) +} + +// Parse parses JWK from the incoming []byte. +// +// For JWK sets, this is a convenience function. You could just as well +// call `json.Unmarshal` against an empty set created by `jwk.NewSet()` +// to parse a JSON buffer into a `jwk.Set`. +// +// This function exists because many times the user does not know before hand +// if a JWK(s) resource at a remote location contains a single JWK key or +// a JWK set, and `jwk.Parse()` can handle either case, returning a JWK Set +// even if the data only contains a single JWK key +// +// If you are looking for more information on how JWKs are parsed, or if +// you know for sure that you have a single key, please see the documentation +// for `jwk.ParseKey()`. +func Parse(src []byte, options ...ParseOption) (Set, error) { + var parsePEM bool + var parseX509 bool + var localReg *json.Registry + var ignoreParseError bool + var pemDecoder PEMDecoder + for _, option := range options { + switch option.Ident() { + case identPEM{}: + if err := option.Value(&parsePEM); err != nil { + return nil, parseerr(`failed to retrieve PEM option value: %w`, err) + } + case identX509{}: + if err := option.Value(&parseX509); err != nil { + return nil, parseerr(`failed to retrieve X509 option value: %w`, err) + } + case identPEMDecoder{}: + if err := option.Value(&pemDecoder); err != nil { + return nil, parseerr(`failed to retrieve PEMDecoder option value: %w`, err) + } + case identIgnoreParseError{}: + if err := option.Value(&ignoreParseError); err != nil { + return nil, parseerr(`failed to retrieve IgnoreParseError option value: %w`, err) + } + case identTypedField{}: + var pair typedFieldPair // temporary var needed for typed field + if err := option.Value(&pair); err != nil { + return nil, parseerr(`failed to retrieve typed field option value: %w`, err) + } + if localReg == nil { + localReg = json.NewRegistry() + } + localReg.Register(pair.Name, pair.Value) + } + } + + s := NewSet() + + if parsePEM || parseX509 { + if pemDecoder == nil { + pemDecoder = NewPEMDecoder() + } + src = bytes.TrimSpace(src) + for len(src) > 0 { + raw, rest, err := pemDecoder.Decode(src) + if err != nil { + return nil, parseerr(`failed to parse PEM encoded key: %w`, err) + } + key, err := Import(raw) + if err != nil { + return nil, parseerr(`failed to create jwk.Key from %T: %w`, raw, err) + } + if err := s.AddKey(key); err != nil { + return nil, parseerr(`failed to add jwk.Key to set: %w`, err) + } + src = bytes.TrimSpace(rest) + } + return s, nil + } + + if localReg != nil || ignoreParseError { + dcKs, ok := s.(KeyWithDecodeCtx) + if !ok { + return nil, parseerr(`typed field was requested, but the key set (%T) does not support DecodeCtx`, s) + } + dc := &setDecodeCtx{ + DecodeCtx: json.NewDecodeCtx(localReg), + ignoreParseError: ignoreParseError, + } + dcKs.SetDecodeCtx(dc) + defer func() { dcKs.SetDecodeCtx(nil) }() + } + + if err := json.Unmarshal(src, s); err != nil { + return nil, parseerr(`failed to unmarshal JWK set: %w`, err) + } + + return s, nil +} + +// ParseReader parses a JWK set from the incoming byte buffer. +func ParseReader(src io.Reader, options ...ParseOption) (Set, error) { + // meh, there's no way to tell if a stream has "ended" a single + // JWKs except when we encounter an EOF, so just... ReadAll + buf, err := io.ReadAll(src) + if err != nil { + return nil, rparseerr(`failed to read from io.Reader: %w`, err) + } + + set, err := Parse(buf, options...) + if err != nil { + return nil, rparseerr(`failed to parse reader: %w`, err) + } + return set, nil +} + +// ParseString parses a JWK set from the incoming string. +func ParseString(s string, options ...ParseOption) (Set, error) { + set, err := Parse([]byte(s), options...) + if err != nil { + return nil, sparseerr(`failed to parse string: %w`, err) + } + return set, nil +} + +// AssignKeyID is a convenience function to automatically assign the "kid" +// section of the key, if it already doesn't have one. It uses Key.Thumbprint +// method with crypto.SHA256 as the default hashing algorithm +func AssignKeyID(key Key, options ...AssignKeyIDOption) error { + if key.Has(KeyIDKey) { + return nil + } + + hash := crypto.SHA256 + for _, option := range options { + switch option.Ident() { + case identThumbprintHash{}: + if err := option.Value(&hash); err != nil { + return fmt.Errorf(`failed to retrieve thumbprint hash option value: %w`, err) + } + } + } + + h, err := key.Thumbprint(hash) + if err != nil { + return fmt.Errorf(`failed to generate thumbprint: %w`, err) + } + + if err := key.Set(KeyIDKey, base64.EncodeToString(h)); err != nil { + return fmt.Errorf(`failed to set "kid": %w`, err) + } + + return nil +} + +// NOTE: may need to remove this to allow pluggale key types +func cloneKey(src Key) (Key, error) { + var dst Key + switch src.(type) { + case RSAPrivateKey: + dst = newRSAPrivateKey() + case RSAPublicKey: + dst = newRSAPublicKey() + case ECDSAPrivateKey: + dst = newECDSAPrivateKey() + case ECDSAPublicKey: + dst = newECDSAPublicKey() + case OKPPrivateKey: + dst = newOKPPrivateKey() + case OKPPublicKey: + dst = newOKPPublicKey() + case SymmetricKey: + dst = newSymmetricKey() + default: + return nil, fmt.Errorf(`jwk.cloneKey: unknown key type %T`, src) + } + + for _, k := range src.Keys() { + // It's absolutely + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`jwk.cloneKey: failed to get %q: %w`, k, err) + } + if err := dst.Set(k, v); err != nil { + return nil, fmt.Errorf(`jwk.cloneKey: failed to set %q: %w`, k, err) + } + } + return dst, nil +} + +// Pem serializes the given jwk.Key in PEM encoded ASN.1 DER format, +// using either PKCS8 for private keys and PKIX for public keys. +// If you need to encode using PKCS1 or SEC1, you must do it yourself. +// +// # Argument must be of type jwk.Key or jwk.Set +// +// Currently only EC (including Ed25519) and RSA keys (and jwk.Set +// comprised of these key types) are supported. +func Pem(v any) ([]byte, error) { + var set Set + switch v := v.(type) { + case Key: + set = NewSet() + if err := set.AddKey(v); err != nil { + return nil, fmt.Errorf(`failed to add key to set: %w`, err) + } + case Set: + set = v + default: + return nil, fmt.Errorf(`argument to Pem must be either jwk.Key or jwk.Set: %T`, v) + } + + var ret []byte + for i := range set.Len() { + key, _ := set.Key(i) + typ, buf, err := asnEncode(key) + if err != nil { + return nil, fmt.Errorf(`failed to encode content for key #%d: %w`, i, err) + } + + var block pem.Block + block.Type = typ + block.Bytes = buf + ret = append(ret, pem.EncodeToMemory(&block)...) + } + return ret, nil +} + +func asnEncode(key Key) (string, []byte, error) { + switch key := key.(type) { + case ECDSAPrivateKey: + var rawkey ecdsa.PrivateKey + if err := Export(key, &rawkey); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key from jwk.Key: %w`, err) + } + buf, err := x509.MarshalECPrivateKey(&rawkey) + if err != nil { + return "", nil, fmt.Errorf(`failed to marshal PKCS8: %w`, err) + } + return pmECPrivateKey, buf, nil + case RSAPrivateKey, OKPPrivateKey: + var rawkey any + if err := Export(key, &rawkey); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key from jwk.Key: %w`, err) + } + buf, err := x509.MarshalPKCS8PrivateKey(rawkey) + if err != nil { + return "", nil, fmt.Errorf(`failed to marshal PKCS8: %w`, err) + } + return pmPrivateKey, buf, nil + case RSAPublicKey, ECDSAPublicKey, OKPPublicKey: + var rawkey any + if err := Export(key, &rawkey); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key from jwk.Key: %w`, err) + } + buf, err := x509.MarshalPKIXPublicKey(rawkey) + if err != nil { + return "", nil, fmt.Errorf(`failed to marshal PKIX: %w`, err) + } + return pmPublicKey, buf, nil + default: + return "", nil, fmt.Errorf(`unsupported key type %T`, key) + } +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jwk.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = key.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC1123 format string: +// +// jwk.RegisterCustomField(`x-birthday`, jwk.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC1123, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} + +// Equal compares two keys and returns true if they are equal. The comparison +// is solely done against the thumbprints of k1 and k2. It is possible for keys +// that have, for example, different key IDs, key usage, etc, to be considered equal. +func Equal(k1, k2 Key) bool { + h := crypto.SHA256 + tp1, err := k1.Thumbprint(h) + if err != nil { + return false // can't report error + } + tp2, err := k2.Thumbprint(h) + if err != nil { + return false // can't report error + } + + return bytes.Equal(tp1, tp2) +} + +// IsPrivateKey returns true if the supplied key is a private key of an +// asymmetric key pair. The argument `k` must implement the `AsymmetricKey` +// interface. +// +// An error is returned if the supplied key is not an `AsymmetricKey`. +func IsPrivateKey(k Key) (bool, error) { + asymmetric, ok := k.(AsymmetricKey) + if ok { + return asymmetric.IsPrivate(), nil + } + return false, fmt.Errorf("jwk.IsPrivateKey: %T is not an asymmetric key", k) +} + +type keyValidationError struct { + err error +} + +func (e *keyValidationError) Error() string { + return fmt.Sprintf(`key validation failed: %s`, e.err) +} + +func (e *keyValidationError) Unwrap() error { + return e.err +} + +func (e *keyValidationError) Is(target error) bool { + _, ok := target.(*keyValidationError) + return ok +} + +// NewKeyValidationError wraps the given error with an error that denotes +// `key.Validate()` has failed. This error type should ONLY be used as +// return value from the `Validate()` method. +func NewKeyValidationError(err error) error { + return &keyValidationError{err: err} +} + +func IsKeyValidationError(err error) bool { + var kve keyValidationError + return errors.Is(err, &kve) +} + +// Configure is used to configure global behavior of the jwk package. +func Configure(options ...GlobalOption) { + var strictKeyUsagePtr *bool + for _, option := range options { + switch option.Ident() { + case identStrictKeyUsage{}: + var v bool + if err := option.Value(&v); err != nil { + continue + } + strictKeyUsagePtr = &v + } + } + + if strictKeyUsagePtr != nil { + strictKeyUsage.Store(*strictKeyUsagePtr) + } +} + +// These are used when validating keys. +type keyWithD interface { + D() ([]byte, bool) +} + +var _ keyWithD = &okpPrivateKey{} + +func extractEmbeddedKey(keyif Key, concretTypes []reflect.Type) (Key, error) { + rv := reflect.ValueOf(keyif) + + // If the value can be converted to one of the concrete types, then we're done + for _, t := range concretTypes { + if rv.Type().ConvertibleTo(t) { + return keyif, nil + } + } + + // When a struct implements the Key interface via embedding, you unfortunately + // cannot use a type switch to determine the concrete type, because + if rv.Kind() == reflect.Ptr { + if rv.IsNil() { + return nil, fmt.Errorf(`invalid key value (0): %w`, ContinueError()) + } + rv = rv.Elem() + } + + if rv.Kind() != reflect.Struct { + return nil, fmt.Errorf(`invalid key value type %T (1): %w`, keyif, ContinueError()) + } + if rv.NumField() == 0 { + return nil, fmt.Errorf(`invalid key value type %T (2): %w`, keyif, ContinueError()) + } + // Iterate through the fields of the struct to find the first field that + // implements the Key interface + rt := rv.Type() + for i := range rv.NumField() { + field := rv.Field(i) + ft := rt.Field(i) + if !ft.Anonymous { + // We can only salvage this object if the object implements jwk.Key + // via embedding, so we skip fields that are not anonymous + continue + } + + if field.CanInterface() { + if k, ok := field.Interface().(Key); ok { + return extractEmbeddedKey(k, concretTypes) + } + } + } + + return nil, fmt.Errorf(`invalid key value type %T (3): %w`, keyif, ContinueError()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/BUILD.bazel new file mode 100644 index 0000000000..68a4ccdc19 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/BUILD.bazel @@ -0,0 +1,17 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "jwkbb", + srcs = ["x509.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jwk/jwkbb", + visibility = ["//visibility:public"], + deps = [ + "@com_github_lestrrat_go_blackmagic//:blackmagic", + ], +) + +alias( + name = "go_default_library", + actual = ":jwkbb", + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/x509.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/x509.go new file mode 100644 index 0000000000..3c827cfa6f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/jwkbb/x509.go @@ -0,0 +1,111 @@ +package jwkbb + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + + "github.com/lestrrat-go/blackmagic" +) + +const ( + PrivateKeyBlockType = `PRIVATE KEY` + PublicKeyBlockType = `PUBLIC KEY` + ECPrivateKeyBlockType = `EC PRIVATE KEY` + RSAPublicKeyBlockType = `RSA PUBLIC KEY` + RSAPrivateKeyBlockType = `RSA PRIVATE KEY` + CertificateBlockType = `CERTIFICATE` +) + +// EncodeX509 encodes the given value into ASN.1 DER format, and returns +// the encoded bytes. The value must be one of the following types: +// *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, +// *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey. +// +// Users can pass a pre-allocated byte slice (but make sure its length is +// changed so that the encoded buffer is appended to the correct location) +// as `dst` to avoid allocations. +func EncodeX509(dst []byte, v any) ([]byte, error) { + var block pem.Block + // Try to convert it into a certificate + switch v := v.(type) { + case *rsa.PrivateKey: + block.Type = RSAPrivateKeyBlockType + block.Bytes = x509.MarshalPKCS1PrivateKey(v) + case *ecdsa.PrivateKey: + marshaled, err := x509.MarshalECPrivateKey(v) + if err != nil { + return nil, err + } + block.Type = ECPrivateKeyBlockType + block.Bytes = marshaled + case ed25519.PrivateKey: + marshaled, err := x509.MarshalPKCS8PrivateKey(v) + if err != nil { + return nil, err + } + block.Type = PrivateKeyBlockType + block.Bytes = marshaled + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: + marshaled, err := x509.MarshalPKIXPublicKey(v) + if err != nil { + return nil, err + } + block.Type = PublicKeyBlockType + block.Bytes = marshaled + default: + return nil, fmt.Errorf(`unsupported type %T for ASN.1 DER encoding`, v) + } + + encoded := pem.EncodeToMemory(&block) + dst = append(dst, encoded...) + return dst, nil +} + +func DecodeX509(dst any, block *pem.Block) error { + switch block.Type { + // Handle the semi-obvious cases + case RSAPrivateKeyBlockType: + key, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKCS1 private key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case RSAPublicKeyBlockType: + key, err := x509.ParsePKCS1PublicKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKCS1 public key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case ECPrivateKeyBlockType: + key, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse EC private key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case PublicKeyBlockType: + // XXX *could* return dsa.PublicKey + key, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKIX public key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case PrivateKeyBlockType: + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse PKCS8 private key: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, key) + case CertificateBlockType: + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf(`failed to parse certificate: %w`, err) + } + return blackmagic.AssignIfCompatible(dst, cert.PublicKey) + default: + return fmt.Errorf(`invalid PEM block type %s`, block.Type) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/key_ops.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/key_ops.go new file mode 100644 index 0000000000..b8c229b3af --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/key_ops.go @@ -0,0 +1,58 @@ +package jwk + +import "fmt" + +func (ops *KeyOperationList) Get() KeyOperationList { + if ops == nil { + return nil + } + return *ops +} + +func (ops *KeyOperationList) Accept(v any) error { + switch x := v.(type) { + case string: + return ops.Accept([]string{x}) + case []any: + l := make([]string, len(x)) + for i, e := range x { + if es, ok := e.(string); ok { + l[i] = es + } else { + return fmt.Errorf(`invalid list element type: expected string, got %T`, v) + } + } + return ops.Accept(l) + case []string: + list := make(KeyOperationList, len(x)) + for i, e := range x { + switch e := KeyOperation(e); e { + case KeyOpSign, KeyOpVerify, KeyOpEncrypt, KeyOpDecrypt, KeyOpWrapKey, KeyOpUnwrapKey, KeyOpDeriveKey, KeyOpDeriveBits: + list[i] = e + default: + return fmt.Errorf(`invalid keyoperation %v`, e) + } + } + + *ops = list + return nil + case []KeyOperation: + list := make(KeyOperationList, len(x)) + for i, e := range x { + switch e { + case KeyOpSign, KeyOpVerify, KeyOpEncrypt, KeyOpDecrypt, KeyOpWrapKey, KeyOpUnwrapKey, KeyOpDeriveKey, KeyOpDeriveBits: + list[i] = e + default: + return fmt.Errorf(`invalid keyoperation %v`, e) + } + } + + *ops = list + return nil + case KeyOperationList: + *ops = x + return nil + default: + return fmt.Errorf(`invalid value %T`, v) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp.go new file mode 100644 index 0000000000..773734b660 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp.go @@ -0,0 +1,321 @@ +package jwk + +import ( + "bytes" + "crypto" + "crypto/ecdh" + "crypto/ed25519" + "fmt" + "reflect" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + RegisterKeyExporter(jwa.OKP(), KeyExportFunc(okpJWKToRaw)) +} + +// Mental note: +// +// Curve25519 refers to a particular curve, and is represented in its Montgomery form. +// +// Ed25519 refers to the biratinally equivalent curve of Curve25519, except it's in Edwards form. +// Ed25519 is the name of the curve and the also the signature scheme using that curve. +// The full name of the scheme is Edwards Curve Digital Signature Algorithm, and thus it is +// also referred to as EdDSA. +// +// X25519 refers to the Diffie-Hellman key exchange protocol that uses Cruve25519. +// Because this is an elliptic curve based Diffie Hellman protocol, it is also referred to +// as ECDH. +// +// OKP keys are used to represent private/public pairs of thse elliptic curve +// keys. But note that the name just means Octet Key Pair. + +func (k *okpPublicKey) Import(rawKeyIf any) error { + k.mu.Lock() + defer k.mu.Unlock() + + var crv jwa.EllipticCurveAlgorithm + switch rawKey := rawKeyIf.(type) { + case ed25519.PublicKey: + k.x = rawKey + crv = jwa.Ed25519() + k.crv = &crv + case *ecdh.PublicKey: + k.x = rawKey.Bytes() + crv = jwa.X25519() + k.crv = &crv + default: + return fmt.Errorf(`unknown key type %T`, rawKeyIf) + } + + return nil +} + +func (k *okpPrivateKey) Import(rawKeyIf any) error { + k.mu.Lock() + defer k.mu.Unlock() + + var crv jwa.EllipticCurveAlgorithm + switch rawKey := rawKeyIf.(type) { + case ed25519.PrivateKey: + k.d = rawKey.Seed() + k.x = rawKey.Public().(ed25519.PublicKey) //nolint:forcetypeassert + crv = jwa.Ed25519() + k.crv = &crv + case *ecdh.PrivateKey: + // k.d = rawKey.Seed() + k.d = rawKey.Bytes() + k.x = rawKey.PublicKey().Bytes() + crv = jwa.X25519() + k.crv = &crv + default: + return fmt.Errorf(`unknown key type %T`, rawKeyIf) + } + + return nil +} + +func buildOKPPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf []byte) (any, error) { + switch alg { + case jwa.Ed25519(): + return ed25519.PublicKey(xbuf), nil + case jwa.X25519(): + ret, err := ecdh.X25519().NewPublicKey(xbuf) + if err != nil { + return nil, fmt.Errorf(`failed to parse x25519 public key %x (size %d): %w`, xbuf, len(xbuf), err) + } + return ret, nil + default: + return nil, fmt.Errorf(`invalid curve algorithm %s`, alg) + } +} + +// Raw returns the EC-DSA public key represented by this JWK +func (k *okpPublicKey) Raw(v any) error { + k.mu.RLock() + defer k.mu.RUnlock() + + crv, ok := k.Crv() + if !ok { + return fmt.Errorf(`missing "crv" field`) + } + + pubk, err := buildOKPPublicKey(crv, k.x) + if err != nil { + return fmt.Errorf(`jwk.OKPPublicKey: failed to build public key: %w`, err) + } + + if err := blackmagic.AssignIfCompatible(v, pubk); err != nil { + return fmt.Errorf(`jwk.OKPPublicKey: failed to assign to destination variable: %w`, err) + } + return nil +} + +func buildOKPPrivateKey(alg jwa.EllipticCurveAlgorithm, xbuf []byte, dbuf []byte) (any, error) { + if len(dbuf) == 0 { + return nil, fmt.Errorf(`cannot use empty seed`) + } + switch alg { + case jwa.Ed25519(): + if len(dbuf) != ed25519.SeedSize { + return nil, fmt.Errorf(`ed25519: wrong private key size`) + } + ret := ed25519.NewKeyFromSeed(dbuf) + //nolint:forcetypeassert + if !bytes.Equal(xbuf, ret.Public().(ed25519.PublicKey)) { + return nil, fmt.Errorf(`ed25519: invalid x value given d value`) + } + return ret, nil + case jwa.X25519(): + ret, err := ecdh.X25519().NewPrivateKey(dbuf) + if err != nil { + return nil, fmt.Errorf(`x25519: unable to construct x25519 private key from seed: %w`, err) + } + return ret, nil + default: + return nil, fmt.Errorf(`invalid curve algorithm %s`, alg) + } +} + +var okpConvertibleKeys = []reflect.Type{ + reflect.TypeOf((*OKPPrivateKey)(nil)).Elem(), + reflect.TypeOf((*OKPPublicKey)(nil)).Elem(), +} + +// This is half baked. I think it will blow up if we used ecdh.* keys and/or x25519 keys +func okpJWKToRaw(key Key, _ any /* this is unused because this is half baked */) (any, error) { + extracted, err := extractEmbeddedKey(key, okpConvertibleKeys) + if err != nil { + return nil, fmt.Errorf(`jwk.OKP: failed to extract embedded key: %w`, err) + } + + switch key := extracted.(type) { + case OKPPrivateKey: + locker, ok := key.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := key.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + x, ok := key.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + + d, ok := key.D() + if !ok { + return nil, fmt.Errorf(`missing "d" field`) + } + + privk, err := buildOKPPrivateKey(crv, x, d) + if err != nil { + return nil, fmt.Errorf(`jwk.OKPPrivateKey: failed to build private key: %w`, err) + } + return privk, nil + case OKPPublicKey: + locker, ok := key.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + crv, ok := key.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + x, ok := key.X() + if !ok { + return nil, fmt.Errorf(`missing "x" field`) + } + pubk, err := buildOKPPublicKey(crv, x) + if err != nil { + return nil, fmt.Errorf(`jwk.OKPPublicKey: failed to build public key: %w`, err) + } + return pubk, nil + default: + return nil, ContinueError() + } +} + +func makeOKPPublicKey(src Key) (Key, error) { + newKey := newOKPPublicKey() + + // Iterate and copy everything except for the bits that should not be in the public key + for _, k := range src.Keys() { + switch k { + case OKPDKey: + continue + default: + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`failed to get field %q: %w`, k, err) + } + + if err := newKey.Set(k, v); err != nil { + return nil, fmt.Errorf(`failed to set field %q: %w`, k, err) + } + } + } + + return newKey, nil +} + +func (k *okpPrivateKey) PublicKey() (Key, error) { + return makeOKPPublicKey(k) +} + +func (k *okpPublicKey) PublicKey() (Key, error) { + return makeOKPPublicKey(k) +} + +func okpThumbprint(hash crypto.Hash, crv, x string) []byte { + h := hash.New() + fmt.Fprint(h, `{"crv":"`) + fmt.Fprint(h, crv) + fmt.Fprint(h, `","kty":"OKP","x":"`) + fmt.Fprint(h, x) + fmt.Fprint(h, `"}`) + return h.Sum(nil) +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 / 8037 +func (k okpPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + return okpThumbprint( + hash, + crv.String(), + base64.EncodeToString(k.x), + ), nil +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 / 8037 +func (k okpPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + crv, ok := k.Crv() + if !ok { + return nil, fmt.Errorf(`missing "crv" field`) + } + + return okpThumbprint( + hash, + crv.String(), + base64.EncodeToString(k.x), + ), nil +} + +func validateOKPKey(key interface { + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) +}) error { + if v, ok := key.Crv(); !ok || v == jwa.InvalidEllipticCurve() { + return fmt.Errorf(`invalid curve algorithm`) + } + + if v, ok := key.X(); !ok || len(v) == 0 { + return fmt.Errorf(`missing "x" field`) + } + + if priv, ok := key.(keyWithD); ok { + if d, ok := priv.D(); !ok || len(d) == 0 { + return fmt.Errorf(`missing "d" field`) + } + } + return nil +} + +func (k *okpPublicKey) Validate() error { + k.mu.RLock() + defer k.mu.RUnlock() + if err := validateOKPKey(k); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.OKPPublicKey: %w`, err)) + } + return nil +} + +func (k *okpPrivateKey) Validate() error { + k.mu.RLock() + defer k.mu.RUnlock() + if err := validateOKPKey(k); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.OKPPrivateKey: %w`, err)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp_gen.go new file mode 100644 index 0000000000..0bde986147 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/okp_gen.go @@ -0,0 +1,1347 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + OKPCrvKey = "crv" + OKPDKey = "d" + OKPXKey = "x" +) + +type OKPPublicKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + X() ([]byte, bool) +} + +type okpPublicKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ OKPPublicKey = &okpPublicKey{} +var _ Key = &okpPublicKey{} + +func newOKPPublicKey() *okpPublicKey { + return &okpPublicKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h okpPublicKey) KeyType() jwa.KeyType { + return jwa.OKP() +} + +func (h okpPublicKey) rlock() { + h.mu.RLock() +} + +func (h okpPublicKey) runlock() { + h.mu.RUnlock() +} + +func (h okpPublicKey) IsPrivate() bool { + return false +} + +func (h *okpPublicKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *okpPublicKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *okpPublicKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *okpPublicKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *okpPublicKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *okpPublicKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *okpPublicKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *okpPublicKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *okpPublicKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *okpPublicKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *okpPublicKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case OKPCrvKey: + return h.crv != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case OKPXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *okpPublicKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`okpPublicKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPCrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *okpPublicKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *okpPublicKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case OKPCrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPCrvKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case OKPXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *okpPublicKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case OKPCrvKey: + k.crv = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case OKPXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *okpPublicKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`okpPublicKey.Clone: %w`, err) + } + return key, nil +} + +func (k *okpPublicKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *okpPublicKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *okpPublicKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.OKP().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case OKPCrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPCrvKey, err) + } + h.crv = &decoded + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case OKPXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + return nil +} + +func (h okpPublicKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 10) + data[KeyTypeKey] = jwa.OKP() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[OKPCrvKey] = *(h.crv) + fields = append(fields, OKPCrvKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[OKPXKey] = h.x + fields = append(fields, OKPXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *okpPublicKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 10+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, OKPCrvKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, OKPXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +type OKPPrivateKey interface { + Key + Crv() (jwa.EllipticCurveAlgorithm, bool) + D() ([]byte, bool) + X() ([]byte, bool) +} + +type okpPrivateKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + crv *jwa.EllipticCurveAlgorithm + d []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + x []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ OKPPrivateKey = &okpPrivateKey{} +var _ Key = &okpPrivateKey{} + +func newOKPPrivateKey() *okpPrivateKey { + return &okpPrivateKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h okpPrivateKey) KeyType() jwa.KeyType { + return jwa.OKP() +} + +func (h okpPrivateKey) rlock() { + h.mu.RLock() +} + +func (h okpPrivateKey) runlock() { + h.mu.RUnlock() +} + +func (h okpPrivateKey) IsPrivate() bool { + return true +} + +func (h *okpPrivateKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *okpPrivateKey) Crv() (jwa.EllipticCurveAlgorithm, bool) { + if h.crv != nil { + return *(h.crv), true + } + return jwa.InvalidEllipticCurve(), false +} + +func (h *okpPrivateKey) D() ([]byte, bool) { + if h.d != nil { + return h.d, true + } + return nil, false +} + +func (h *okpPrivateKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *okpPrivateKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *okpPrivateKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *okpPrivateKey) X() ([]byte, bool) { + if h.x != nil { + return h.x, true + } + return nil, false +} + +func (h *okpPrivateKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *okpPrivateKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *okpPrivateKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *okpPrivateKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *okpPrivateKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case OKPCrvKey: + return h.crv != nil + case OKPDKey: + return h.d != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case OKPXKey: + return h.x != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *okpPrivateKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`okpPrivateKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPCrvKey: + if h.crv == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.crv)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPDKey: + if h.d == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.d); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case OKPXKey: + if h.x == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *okpPrivateKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *okpPrivateKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case OKPCrvKey: + if v, ok := value.(jwa.EllipticCurveAlgorithm); ok { + h.crv = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPCrvKey, value) + case OKPDKey: + if v, ok := value.([]byte); ok { + h.d = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPDKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case OKPXKey: + if v, ok := value.([]byte); ok { + h.x = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, OKPXKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *okpPrivateKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case OKPCrvKey: + k.crv = nil + case OKPDKey: + k.d = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case OKPXKey: + k.x = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *okpPrivateKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`okpPrivateKey.Clone: %w`, err) + } + return key, nil +} + +func (k *okpPrivateKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *okpPrivateKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *okpPrivateKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.crv = nil + h.d = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.x = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.OKP().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case OKPCrvKey: + var decoded jwa.EllipticCurveAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPCrvKey, err) + } + h.crv = &decoded + case OKPDKey: + if err := json.AssignNextBytesToken(&h.d, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPDKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case OKPXKey: + if err := json.AssignNextBytesToken(&h.x, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, OKPXKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.crv == nil { + return fmt.Errorf(`required field crv is missing`) + } + if h.d == nil { + return fmt.Errorf(`required field d is missing`) + } + if h.x == nil { + return fmt.Errorf(`required field x is missing`) + } + return nil +} + +func (h okpPrivateKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 11) + data[KeyTypeKey] = jwa.OKP() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.crv != nil { + data[OKPCrvKey] = *(h.crv) + fields = append(fields, OKPCrvKey) + } + if h.d != nil { + data[OKPDKey] = h.d + fields = append(fields, OKPDKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.x != nil { + data[OKPXKey] = h.x + fields = append(fields, OKPXKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *okpPrivateKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 11+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.crv != nil { + keys = append(keys, OKPCrvKey) + } + if h.d != nil { + keys = append(keys, OKPDKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.x != nil { + keys = append(keys, OKPXKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var okpStandardFields KeyFilter + +func init() { + okpStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, OKPCrvKey, OKPXKey, OKPDKey) +} + +// OKPStandardFieldsFilter returns a KeyFilter that filters out standard OKP fields. +func OKPStandardFieldsFilter() KeyFilter { + return okpStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.go new file mode 100644 index 0000000000..56cc52625f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.go @@ -0,0 +1,76 @@ +package jwk + +import ( + "time" + + "github.com/lestrrat-go/httprc/v3" + "github.com/lestrrat-go/option/v2" +) + +type identTypedField struct{} + +type typedFieldPair struct { + Name string + Value any +} + +// WithTypedField allows a private field to be parsed into the object type of +// your choice. It works much like the RegisterCustomField, but the effect +// is only applicable to the jwt.Parse function call which receives this option. +// +// While this can be extremely useful, this option should be used with caution: +// There are many caveats that your entire team/user-base needs to be aware of, +// and therefore in general its use is discouraged. Only use it when you know +// what you are doing, and you document its use clearly for others. +// +// First and foremost, this is a "per-object" option. Meaning that given the same +// serialized format, it is possible to generate two objects whose internal +// representations may differ. That is, if you parse one _WITH_ the option, +// and the other _WITHOUT_, their internal representation may completely differ. +// This could potentially lead to problems. +// +// Second, specifying this option will slightly slow down the decoding process +// as it needs to consult multiple definitions sources (global and local), so +// be careful if you are decoding a large number of tokens, as the effects will stack up. +func WithTypedField(name string, object any) ParseOption { + return &parseOption{ + option.New(identTypedField{}, + typedFieldPair{Name: name, Value: object}, + ), + } +} + +type registerResourceOption struct { + option.Interface +} + +func (registerResourceOption) registerOption() {} +func (registerResourceOption) resourceOption() {} + +type identNewResourceOption struct{} + +// WithHttprcResourceOption can be used to pass arbitrary `httprc.NewResourceOption` +// to `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithHttprcResourceOption(o httprc.NewResourceOption) RegisterOption { + return ®isterResourceOption{ + option.New(identNewResourceOption{}, o), + } +} + +// WithConstantInterval can be used to pass `httprc.WithConstantInterval` option to +// `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithConstantInterval(d time.Duration) RegisterOption { + return WithHttprcResourceOption(httprc.WithConstantInterval(d)) +} + +// WithMinInterval can be used to pass `httprc.WithMinInterval` option to +// `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithMinInterval(d time.Duration) RegisterOption { + return WithHttprcResourceOption(httprc.WithMinInterval(d)) +} + +// WithMaxInterval can be used to pass `httprc.WithMaxInterval` option to +// `(httprc.Client).Add` by way of `(jwk.Cache).Register`. +func WithMaxInterval(d time.Duration) RegisterOption { + return WithHttprcResourceOption(httprc.WithMaxInterval(d)) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.yaml new file mode 100644 index 0000000000..879dcba158 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options.yaml @@ -0,0 +1,143 @@ +package_name: jwk +output: jwk/options_gen.go +interfaces: + - name: CacheOption + comment: | + CacheOption is a type of Option that can be passed to the + the `jwk.NewCache()` function. + - name: ResourceOption + comment: | + ResourceOption is a type of Option that can be passed to the `httprc.NewResource` function + by way of RegisterOption. + - name: AssignKeyIDOption + - name: FetchOption + methods: + - fetchOption + - parseOption + - registerOption + comment: | + FetchOption is a type of Option that can be passed to `jwk.Fetch()` + FetchOption also implements the `RegisterOption`, and thus can + safely be passed to `(*jwk.Cache).Register()` + - name: ParseOption + methods: + - fetchOption + - registerOption + - readFileOption + comment: | + ParseOption is a type of Option that can be passed to `jwk.Parse()` + ParseOption also implements the `ReadFileOption` and `NewCacheOption`, + and thus safely be passed to `jwk.ReadFile` and `(*jwk.Cache).Configure()` + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwk.ReadFile` + - name: RegisterOption + comment: | + RegisterOption describes options that can be passed to `(jwk.Cache).Register()` + - name: RegisterFetchOption + methods: + - fetchOption + - registerOption + - parseOption + comment: | + RegisterFetchOption describes options that can be passed to `(jwk.Cache).Register()` and `jwk.Fetch()` + - name: GlobalOption + comment: | + GlobalOption is a type of Option that can be passed to the `jwk.Configure()` to + change the global configuration of the jwk package. +options: + - ident: HTTPClient + interface: RegisterFetchOption + argument_type: HTTPClient + comment: | + WithHTTPClient allows users to specify the "net/http".Client object that + is used when fetching jwk.Set objects. + - ident: ThumbprintHash + interface: AssignKeyIDOption + argument_type: crypto.Hash + - ident: LocalRegistry + option_name: withLocalRegistry + interface: ParseOption + argument_type: '*json.Registry' + comment: This option is only available for internal code. Users don't get to play with it + - ident: PEM + interface: ParseOption + argument_type: bool + comment: | + WithPEM specifies that the input to `Parse()` is a PEM encoded key. + + This option is planned to be deprecated in the future. The plan is to + replace it with `jwk.WithX509(true)` + - ident: X509 + interface: ParseOption + argument_type: bool + comment: | + WithX509 specifies that the input to `Parse()` is an X.509 encoded key + - ident: PEMDecoder + interface: ParseOption + argument_type: PEMDecoder + comment: | + WithPEMDecoder specifies the PEMDecoder object to use when decoding + PEM encoded keys. This option can be passed to `jwk.Parse()` + + This option is planned to be deprecated in the future. The plan is to + use `jwk.RegisterX509Decoder()` to register a custom X.509 decoder globally. + - ident: FetchWhitelist + interface: FetchOption + argument_type: Whitelist + comment: | + WithFetchWhitelist specifies the Whitelist object to use when + fetching JWKs from a remote source. This option can be passed + to both `jwk.Fetch()` + - ident: IgnoreParseError + interface: ParseOption + argument_type: bool + comment: | + WithIgnoreParseError is only applicable when used with `jwk.Parse()` + (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function + will return an error no matter what the input is. + + DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST. + + The option specifies that errors found during parsing of individual + keys are ignored. For example, if you had keys A, B, C where B is + invalid (e.g. it does not contain the required fields), then the + resulting JWKS will contain keys A and C only. + + This options exists as an escape hatch for those times when a + key in a JWKS that is irrelevant for your use case is causing + your JWKS parsing to fail, and you want to get to the rest of the + keys in the JWKS. + + Again, DO NOT USE unless you have exhausted all other routes. + When you use this option, you will not be able to tell if you are + using a faulty JWKS, except for when there are JSON syntax errors. + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: WaitReady + interface: RegisterOption + argument_type: bool + comment: | + WithWaitReady specifies that the `jwk.Cache` should wait until the + first fetch is done before returning from the `Register()` call. + + This option is by default true. Specify a false value if you would + like to return immediately from the `Register()` call. + + This options is exactly the same as `httprc.WithWaitReady()` + - ident: StrictKeyUsage + interface: GlobalOption + argument_type: bool + comment: | + WithStrictKeyUsage specifies if during JWK parsing, the "use" field + should be confined to the values that have been registered via + `jwk.RegisterKeyType()`. By default this option is true, and the + initial allowed values are "use" and "enc" only. + + If this option is set to false, then the "use" field can be any + value. If this options is set to true, then the "use" field must + be one of the registered values, and otherwise an error will be + reported during parsing / assignment to `jwk.KeyUsageType` \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options_gen.go new file mode 100644 index 0000000000..99e66c3e7e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/options_gen.go @@ -0,0 +1,297 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwk + +import ( + "crypto" + "io/fs" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +type AssignKeyIDOption interface { + Option + assignKeyIDOption() +} + +type assignKeyIDOption struct { + Option +} + +func (*assignKeyIDOption) assignKeyIDOption() {} + +// CacheOption is a type of Option that can be passed to the +// the `jwk.NewCache()` function. +type CacheOption interface { + Option + cacheOption() +} + +type cacheOption struct { + Option +} + +func (*cacheOption) cacheOption() {} + +// FetchOption is a type of Option that can be passed to `jwk.Fetch()` +// FetchOption also implements the `RegisterOption`, and thus can +// safely be passed to `(*jwk.Cache).Register()` +type FetchOption interface { + Option + fetchOption() + parseOption() + registerOption() +} + +type fetchOption struct { + Option +} + +func (*fetchOption) fetchOption() {} + +func (*fetchOption) parseOption() {} + +func (*fetchOption) registerOption() {} + +// GlobalOption is a type of Option that can be passed to the `jwk.Configure()` to +// change the global configuration of the jwk package. +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// ParseOption is a type of Option that can be passed to `jwk.Parse()` +// ParseOption also implements the `ReadFileOption` and `NewCacheOption`, +// and thus safely be passed to `jwk.ReadFile` and `(*jwk.Cache).Configure()` +type ParseOption interface { + Option + fetchOption() + registerOption() + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) fetchOption() {} + +func (*parseOption) registerOption() {} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwk.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// RegisterFetchOption describes options that can be passed to `(jwk.Cache).Register()` and `jwk.Fetch()` +type RegisterFetchOption interface { + Option + fetchOption() + registerOption() + parseOption() +} + +type registerFetchOption struct { + Option +} + +func (*registerFetchOption) fetchOption() {} + +func (*registerFetchOption) registerOption() {} + +func (*registerFetchOption) parseOption() {} + +// RegisterOption describes options that can be passed to `(jwk.Cache).Register()` +type RegisterOption interface { + Option + registerOption() +} + +type registerOption struct { + Option +} + +func (*registerOption) registerOption() {} + +// ResourceOption is a type of Option that can be passed to the `httprc.NewResource` function +// by way of RegisterOption. +type ResourceOption interface { + Option + resourceOption() +} + +type resourceOption struct { + Option +} + +func (*resourceOption) resourceOption() {} + +type identFS struct{} +type identFetchWhitelist struct{} +type identHTTPClient struct{} +type identIgnoreParseError struct{} +type identLocalRegistry struct{} +type identPEM struct{} +type identPEMDecoder struct{} +type identStrictKeyUsage struct{} +type identThumbprintHash struct{} +type identWaitReady struct{} +type identX509 struct{} + +func (identFS) String() string { + return "WithFS" +} + +func (identFetchWhitelist) String() string { + return "WithFetchWhitelist" +} + +func (identHTTPClient) String() string { + return "WithHTTPClient" +} + +func (identIgnoreParseError) String() string { + return "WithIgnoreParseError" +} + +func (identLocalRegistry) String() string { + return "withLocalRegistry" +} + +func (identPEM) String() string { + return "WithPEM" +} + +func (identPEMDecoder) String() string { + return "WithPEMDecoder" +} + +func (identStrictKeyUsage) String() string { + return "WithStrictKeyUsage" +} + +func (identThumbprintHash) String() string { + return "WithThumbprintHash" +} + +func (identWaitReady) String() string { + return "WithWaitReady" +} + +func (identX509) String() string { + return "WithX509" +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +// WithFetchWhitelist specifies the Whitelist object to use when +// fetching JWKs from a remote source. This option can be passed +// to both `jwk.Fetch()` +func WithFetchWhitelist(v Whitelist) FetchOption { + return &fetchOption{option.New(identFetchWhitelist{}, v)} +} + +// WithHTTPClient allows users to specify the "net/http".Client object that +// is used when fetching jwk.Set objects. +func WithHTTPClient(v HTTPClient) RegisterFetchOption { + return ®isterFetchOption{option.New(identHTTPClient{}, v)} +} + +// WithIgnoreParseError is only applicable when used with `jwk.Parse()` +// (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function +// will return an error no matter what the input is. +// +// DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST. +// +// The option specifies that errors found during parsing of individual +// keys are ignored. For example, if you had keys A, B, C where B is +// invalid (e.g. it does not contain the required fields), then the +// resulting JWKS will contain keys A and C only. +// +// This options exists as an escape hatch for those times when a +// key in a JWKS that is irrelevant for your use case is causing +// your JWKS parsing to fail, and you want to get to the rest of the +// keys in the JWKS. +// +// Again, DO NOT USE unless you have exhausted all other routes. +// When you use this option, you will not be able to tell if you are +// using a faulty JWKS, except for when there are JSON syntax errors. +func WithIgnoreParseError(v bool) ParseOption { + return &parseOption{option.New(identIgnoreParseError{}, v)} +} + +// This option is only available for internal code. Users don't get to play with it +func withLocalRegistry(v *json.Registry) ParseOption { + return &parseOption{option.New(identLocalRegistry{}, v)} +} + +// WithPEM specifies that the input to `Parse()` is a PEM encoded key. +// +// This option is planned to be deprecated in the future. The plan is to +// replace it with `jwk.WithX509(true)` +func WithPEM(v bool) ParseOption { + return &parseOption{option.New(identPEM{}, v)} +} + +// WithPEMDecoder specifies the PEMDecoder object to use when decoding +// PEM encoded keys. This option can be passed to `jwk.Parse()` +// +// This option is planned to be deprecated in the future. The plan is to +// use `jwk.RegisterX509Decoder()` to register a custom X.509 decoder globally. +func WithPEMDecoder(v PEMDecoder) ParseOption { + return &parseOption{option.New(identPEMDecoder{}, v)} +} + +// WithStrictKeyUsage specifies if during JWK parsing, the "use" field +// should be confined to the values that have been registered via +// `jwk.RegisterKeyType()`. By default this option is true, and the +// initial allowed values are "use" and "enc" only. +// +// If this option is set to false, then the "use" field can be any +// value. If this options is set to true, then the "use" field must +// be one of the registered values, and otherwise an error will be +// reported during parsing / assignment to `jwk.KeyUsageType` +func WithStrictKeyUsage(v bool) GlobalOption { + return &globalOption{option.New(identStrictKeyUsage{}, v)} +} + +func WithThumbprintHash(v crypto.Hash) AssignKeyIDOption { + return &assignKeyIDOption{option.New(identThumbprintHash{}, v)} +} + +// WithWaitReady specifies that the `jwk.Cache` should wait until the +// first fetch is done before returning from the `Register()` call. +// +// This option is by default true. Specify a false value if you would +// like to return immediately from the `Register()` call. +// +// This options is exactly the same as `httprc.WithWaitReady()` +func WithWaitReady(v bool) RegisterOption { + return ®isterOption{option.New(identWaitReady{}, v)} +} + +// WithX509 specifies that the input to `Parse()` is an X.509 encoded key +func WithX509(v bool) ParseOption { + return &parseOption{option.New(identX509{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/parser.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/parser.go new file mode 100644 index 0000000000..fa8764ef72 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/parser.go @@ -0,0 +1,244 @@ +package jwk + +import ( + "fmt" + "reflect" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// KeyParser represents a type that can parse a JSON representation of a JWK into +// a jwk.Key. +// See KeyConvertor for a type that can convert a raw key into a jwk.Key +type KeyParser interface { + // ParseKey parses a JSON payload to a `jwk.Key` object. The first + // argument is an object that contains some hints as to what kind of + // key the JSON payload contains. + // + // If your KeyParser decides that the payload is not something + // you can parse, and you would like to continue parsing with + // the remaining KeyParser instances that are registered, + // return a `jwk.ContinueParseError`. Any other errors will immediately + // halt the parsing process. + // + // When unmarshaling JSON, use the unmarshaler object supplied as + // the second argument. This will ensure that the JSON is unmarshaled + // in a way that is compatible with the rest of the library. + ParseKey(probe *KeyProbe, unmarshaler KeyUnmarshaler, payload []byte) (Key, error) +} + +// KeyParseFunc is a type of KeyParser that is based on a function/closure +type KeyParseFunc func(probe *KeyProbe, unmarshaler KeyUnmarshaler, payload []byte) (Key, error) + +func (f KeyParseFunc) ParseKey(probe *KeyProbe, unmarshaler KeyUnmarshaler, payload []byte) (Key, error) { + return f(probe, unmarshaler, payload) +} + +// protects keyParsers +var muKeyParser sync.RWMutex + +// list of parsers +var keyParsers = []KeyParser{KeyParseFunc(defaultParseKey)} + +// RegisterKeyParser adds a new KeyParser. Parsers are called in FILO order. +// That is, the last parser to be registered is called first. There is no +// check for duplicate entries. +func RegisterKeyParser(kp KeyParser) { + muKeyParser.Lock() + defer muKeyParser.Unlock() + keyParsers = append(keyParsers, kp) +} + +func defaultParseKey(probe *KeyProbe, unmarshaler KeyUnmarshaler, data []byte) (Key, error) { + var key Key + var kty string + var d json.RawMessage + if err := probe.Get("Kty", &kty); err != nil { + return nil, fmt.Errorf(`jwk.Parse: failed to get "kty" hint: %w`, err) + } + // We ignore errors from this field, as it's optional + _ = probe.Get("D", &d) + switch v, _ := jwa.LookupKeyType(kty); v { + case jwa.RSA(): + if d != nil { + key = newRSAPrivateKey() + } else { + key = newRSAPublicKey() + } + case jwa.EC(): + if d != nil { + key = newECDSAPrivateKey() + } else { + key = newECDSAPublicKey() + } + case jwa.OctetSeq(): + key = newSymmetricKey() + case jwa.OKP(): + if d != nil { + key = newOKPPrivateKey() + } else { + key = newOKPPublicKey() + } + default: + return nil, fmt.Errorf(`invalid key type from JSON (%s)`, kty) + } + + if err := unmarshaler.UnmarshalKey(data, key); err != nil { + return nil, fmt.Errorf(`failed to unmarshal JSON into key (%T): %w`, key, err) + } + return key, nil +} + +type keyUnmarshaler struct { + localReg *json.Registry +} + +func (ku *keyUnmarshaler) UnmarshalKey(data []byte, key any) error { + if ku.localReg != nil { + dcKey, ok := key.(json.DecodeCtxContainer) + if !ok { + return fmt.Errorf(`typed field was requested, but the key (%T) does not support DecodeCtx`, key) + } + dc := json.NewDecodeCtx(ku.localReg) + dcKey.SetDecodeCtx(dc) + defer func() { dcKey.SetDecodeCtx(nil) }() + } + + if err := json.Unmarshal(data, key); err != nil { + return fmt.Errorf(`failed to unmarshal JSON into key (%T): %w`, key, err) + } + + return nil +} + +// keyProber is the object that starts the probing. When Probe() is called, +// it creates (possibly from a cached value) an object that is used to +// hold hint values. +type keyProber struct { + mu sync.RWMutex + pool *sync.Pool + fields map[string]reflect.StructField + typ reflect.Type +} + +func (kp *keyProber) AddField(field reflect.StructField) error { + kp.mu.Lock() + defer kp.mu.Unlock() + + if _, ok := kp.fields[field.Name]; ok { + return fmt.Errorf(`field name %s is already registered`, field.Name) + } + kp.fields[field.Name] = field + kp.makeStructType() + + // Update pool (note: the logic is the same, but we need to recreate it + // so that we don't accidentally use old stored values) + kp.pool = &sync.Pool{ + New: kp.makeStruct, + } + return nil +} + +func (kp *keyProber) makeStructType() { + // DOES NOT LOCK + fields := make([]reflect.StructField, 0, len(kp.fields)) + for _, f := range kp.fields { + fields = append(fields, f) + } + kp.typ = reflect.StructOf(fields) +} + +func (kp *keyProber) makeStruct() any { + return reflect.New(kp.typ) +} + +func (kp *keyProber) Probe(data []byte) (*KeyProbe, error) { + kp.mu.RLock() + defer kp.mu.RUnlock() + + // if the field list unchanged, so is the pool object, so effectively + // we should be using the cached version + v := kp.pool.Get() + if v == nil { + return nil, fmt.Errorf(`probe: failed to get object from pool`) + } + rv, ok := v.(reflect.Value) + if !ok { + return nil, fmt.Errorf(`probe: value returned from pool as of type %T, expected reflect.Value`, v) + } + + if err := json.Unmarshal(data, rv.Interface()); err != nil { + return nil, fmt.Errorf(`probe: failed to unmarshal data: %w`, err) + } + + return &KeyProbe{data: rv}, nil +} + +// KeyProbe is the object that carries the hints when parsing a key. +// The exact list of fields can vary depending on the types of key +// that are registered. +// +// Use `Get()` to access the value of a field. +// +// The underlying data stored in a KeyProbe is recycled each +// time a value is parsed, therefore you are not allowed to hold +// onto this object after ParseKey() is done. +type KeyProbe struct { + data reflect.Value +} + +// Get returns the value of the field with the given `name“. +// `dst` must be a pointer to a value that can hold the type of +// the value of the field, which is determined by the +// field type registered through `jwk.RegisterProbeField()` +func (kp *KeyProbe) Get(name string, dst any) error { + f := kp.data.Elem().FieldByName(name) + if !f.IsValid() { + return fmt.Errorf(`field %s not found`, name) + } + + if err := blackmagic.AssignIfCompatible(dst, f.Addr().Interface()); err != nil { + return fmt.Errorf(`failed to assign value of field %q to %T: %w`, name, dst, err) + } + return nil +} + +// We don't really need the object, we need to know its type +var keyProbe = &keyProber{ + fields: make(map[string]reflect.StructField), +} + +// RegisterProbeField adds a new field to be probed during the initial +// phase of parsing. This is done by partially parsing the JSON payload, +// and we do this by calling `json.Unmarshal` using a dynamic type that +// can possibly be modified during runtime. This function is used to +// add a new field to this dynamic type. +// +// Note that the `Name` field for the given `reflect.StructField` must start +// with an upper case alphabet, such that it is treated as an exported field. +// So for example, if you want to probe the "my_hint" field, you should specify +// the field name as "MyHint" or similar. +// +// Also the field name must be unique. If you believe that your field name may +// collide with other packages that may want to add their own probes, +// it is the responsibility of the caller +// to ensure that the field name is unique (possibly by prefixing the field +// name with a unique string). It is important to note that the field name +// need not be the same as the JSON field name. For example, your field name +// could be "MyPkg_MyHint", while the actual JSON field name could be "my_hint". +// +// If the field name is not unique, an error is returned. +func RegisterProbeField(p reflect.StructField) error { + // locking is done inside keyProbe + return keyProbe.AddField(p) +} + +// KeyUnmarshaler is a thin wrapper around json.Unmarshal. It behaves almost +// exactly like json.Unmarshal, but it allows us to add extra magic that +// is specific to this library before calling the actual json.Unmarshal. +type KeyUnmarshaler interface { + UnmarshalKey(data []byte, key any) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa.go new file mode 100644 index 0000000000..bcd7d05c02 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa.go @@ -0,0 +1,360 @@ +package jwk + +import ( + "crypto" + "crypto/rsa" + "encoding/binary" + "fmt" + "math/big" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + RegisterKeyExporter(jwa.RSA(), KeyExportFunc(rsaJWKToRaw)) +} + +func (k *rsaPrivateKey) Import(rawKey *rsa.PrivateKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + d, err := bigIntToBytes(rawKey.D) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.d = d + + l := len(rawKey.Primes) + + if l < 0 /* I know, I'm being paranoid */ || l > 2 { + return fmt.Errorf(`invalid number of primes in rsa.PrivateKey: need 0 to 2, but got %d`, len(rawKey.Primes)) + } + + if l > 0 { + p, err := bigIntToBytes(rawKey.Primes[0]) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.p = p + } + + if l > 1 { + q, err := bigIntToBytes(rawKey.Primes[1]) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.q = q + } + + // dp, dq, qi are optional values + if v, err := bigIntToBytes(rawKey.Precomputed.Dp); err == nil { + k.dp = v + } + if v, err := bigIntToBytes(rawKey.Precomputed.Dq); err == nil { + k.dq = v + } + if v, err := bigIntToBytes(rawKey.Precomputed.Qinv); err == nil { + k.qi = v + } + + // public key part + n, e, err := importRsaPublicKeyByteValues(&rawKey.PublicKey) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.n = n + k.e = e + + return nil +} + +func importRsaPublicKeyByteValues(rawKey *rsa.PublicKey) ([]byte, []byte, error) { + n, err := bigIntToBytes(rawKey.N) + if err != nil { + return nil, nil, fmt.Errorf(`invalid rsa.PublicKey: %w`, err) + } + + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, uint64(rawKey.E)) + i := 0 + for ; i < len(data); i++ { + if data[i] != 0x0 { + break + } + } + return n, data[i:], nil +} + +func (k *rsaPublicKey) Import(rawKey *rsa.PublicKey) error { + k.mu.Lock() + defer k.mu.Unlock() + + n, e, err := importRsaPublicKeyByteValues(rawKey) + if err != nil { + return fmt.Errorf(`invalid rsa.PrivateKey: %w`, err) + } + k.n = n + k.e = e + + return nil +} + +func buildRSAPublicKey(key *rsa.PublicKey, n, e []byte) { + bin := pool.BigInt().Get() + bie := pool.BigInt().Get() + defer pool.BigInt().Put(bie) + + bin.SetBytes(n) + bie.SetBytes(e) + + key.N = bin + key.E = int(bie.Int64()) +} + +var rsaConvertibleKeys = []reflect.Type{ + reflect.TypeOf((*RSAPrivateKey)(nil)).Elem(), + reflect.TypeOf((*RSAPublicKey)(nil)).Elem(), +} + +func rsaJWKToRaw(key Key, hint any) (any, error) { + extracted, err := extractEmbeddedKey(key, rsaConvertibleKeys) + if err != nil { + return nil, fmt.Errorf(`failed to extract embedded key: %w`, err) + } + switch key := extracted.(type) { + case RSAPrivateKey: + switch hint.(type) { + case *rsa.PrivateKey, *any: + default: + return nil, fmt.Errorf(`invalid destination object type %T for private RSA JWK: %w`, hint, ContinueError()) + } + + locker, ok := key.(rlocker) + if !ok { + locker.rlock() + defer locker.runlock() + } + + od, ok := key.D() + if !ok { + return nil, fmt.Errorf(`missing "d" value`) + } + + oq, ok := key.Q() + if !ok { + return nil, fmt.Errorf(`missing "q" value`) + } + + op, ok := key.P() + if !ok { + return nil, fmt.Errorf(`missing "p" value`) + } + + var d, q, p big.Int // note: do not use from sync.Pool + + d.SetBytes(od) + q.SetBytes(oq) + p.SetBytes(op) + + // optional fields + var dp, dq, qi *big.Int + + if odp, ok := key.DP(); ok { + dp = &big.Int{} // note: do not use from sync.Pool + dp.SetBytes(odp) + } + + if odq, ok := key.DQ(); ok { + dq = &big.Int{} // note: do not use from sync.Pool + dq.SetBytes(odq) + } + + if oqi, ok := key.QI(); ok { + qi = &big.Int{} // note: do not use from sync.Pool + qi.SetBytes(oqi) + } + + n, ok := key.N() + if !ok { + return nil, fmt.Errorf(`missing "n" value`) + } + + e, ok := key.E() + if !ok { + return nil, fmt.Errorf(`missing "e" value`) + } + + var privkey rsa.PrivateKey + buildRSAPublicKey(&privkey.PublicKey, n, e) + privkey.D = &d + privkey.Primes = []*big.Int{&p, &q} + + if dp != nil { + privkey.Precomputed.Dp = dp + } + if dq != nil { + privkey.Precomputed.Dq = dq + } + if qi != nil { + privkey.Precomputed.Qinv = qi + } + // This may look like a no-op, but it's required if we want to + // compare it against a key generated by rsa.GenerateKey + privkey.Precomputed.CRTValues = []rsa.CRTValue{} + return &privkey, nil + case RSAPublicKey: + switch hint.(type) { + case *rsa.PublicKey, *any: + default: + return nil, fmt.Errorf(`invalid destination object type %T for public RSA JWK: %w`, hint, ContinueError()) + } + + locker, ok := key.(rlocker) + if !ok { + locker.rlock() + defer locker.runlock() + } + + n, ok := key.N() + if !ok { + return nil, fmt.Errorf(`missing "n" value`) + } + + e, ok := key.E() + if !ok { + return nil, fmt.Errorf(`missing "e" value`) + } + + var pubkey rsa.PublicKey + buildRSAPublicKey(&pubkey, n, e) + + return &pubkey, nil + + default: + return nil, ContinueError() + } +} + +func makeRSAPublicKey(src Key) (Key, error) { + newKey := newRSAPublicKey() + + // Iterate and copy everything except for the bits that should not be in the public key + for _, k := range src.Keys() { + switch k { + case RSADKey, RSADPKey, RSADQKey, RSAPKey, RSAQKey, RSAQIKey: + continue + default: + var v any + if err := src.Get(k, &v); err != nil { + return nil, fmt.Errorf(`rsa: makeRSAPublicKey: failed to get field %q: %w`, k, err) + } + if err := newKey.Set(k, v); err != nil { + return nil, fmt.Errorf(`rsa: makeRSAPublicKey: failed to set field %q: %w`, k, err) + } + } + } + + return newKey, nil +} + +func (k *rsaPrivateKey) PublicKey() (Key, error) { + return makeRSAPublicKey(k) +} + +func (k *rsaPublicKey) PublicKey() (Key, error) { + return makeRSAPublicKey(k) +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k rsaPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key rsa.PrivateKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export RSA private key: %w`, err) + } + return rsaThumbprint(hash, &key.PublicKey) +} + +func (k rsaPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + + var key rsa.PublicKey + if err := Export(&k, &key); err != nil { + return nil, fmt.Errorf(`failed to export RSA public key: %w`, err) + } + return rsaThumbprint(hash, &key) +} + +func rsaThumbprint(hash crypto.Hash, key *rsa.PublicKey) ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(`{"e":"`) + buf.WriteString(base64.EncodeUint64ToString(uint64(key.E))) + buf.WriteString(`","kty":"RSA","n":"`) + buf.WriteString(base64.EncodeToString(key.N.Bytes())) + buf.WriteString(`"}`) + + h := hash.New() + if _, err := buf.WriteTo(h); err != nil { + return nil, fmt.Errorf(`failed to write rsaThumbprint: %w`, err) + } + return h.Sum(nil), nil +} + +func validateRSAKey(key interface { + N() ([]byte, bool) + E() ([]byte, bool) +}, checkPrivate bool) error { + n, ok := key.N() + if !ok { + return fmt.Errorf(`missing "n" value`) + } + + e, ok := key.E() + if !ok { + return fmt.Errorf(`missing "e" value`) + } + + if len(n) == 0 { + // Ideally we would like to check for the actual length, but unlike + // EC keys, we have nothing in the key itself that will tell us + // how many bits this key should have. + return fmt.Errorf(`missing "n" value`) + } + if len(e) == 0 { + return fmt.Errorf(`missing "e" value`) + } + if checkPrivate { + if priv, ok := key.(keyWithD); ok { + if d, ok := priv.D(); !ok || len(d) == 0 { + return fmt.Errorf(`missing "d" value`) + } + } else { + return fmt.Errorf(`missing "d" value`) + } + } + + return nil +} + +func (k *rsaPrivateKey) Validate() error { + if err := validateRSAKey(k, true); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.RSAPrivateKey: %w`, err)) + } + return nil +} + +func (k *rsaPublicKey) Validate() error { + if err := validateRSAKey(k, false); err != nil { + return NewKeyValidationError(fmt.Errorf(`jwk.RSAPublicKey: %w`, err)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa_gen.go new file mode 100644 index 0000000000..8e2a4f085b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/rsa_gen.go @@ -0,0 +1,1543 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + RSADKey = "d" + RSADPKey = "dp" + RSADQKey = "dq" + RSAEKey = "e" + RSANKey = "n" + RSAPKey = "p" + RSAQIKey = "qi" + RSAQKey = "q" +) + +type RSAPublicKey interface { + Key + E() ([]byte, bool) + N() ([]byte, bool) +} + +type rsaPublicKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + e []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + n []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ RSAPublicKey = &rsaPublicKey{} +var _ Key = &rsaPublicKey{} + +func newRSAPublicKey() *rsaPublicKey { + return &rsaPublicKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h rsaPublicKey) KeyType() jwa.KeyType { + return jwa.RSA() +} + +func (h rsaPublicKey) rlock() { + h.mu.RLock() +} + +func (h rsaPublicKey) runlock() { + h.mu.RUnlock() +} + +func (h rsaPublicKey) IsPrivate() bool { + return false +} + +func (h *rsaPublicKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *rsaPublicKey) E() ([]byte, bool) { + if h.e != nil { + return h.e, true + } + return nil, false +} + +func (h *rsaPublicKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *rsaPublicKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *rsaPublicKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *rsaPublicKey) N() ([]byte, bool) { + if h.n != nil { + return h.n, true + } + return nil, false +} + +func (h *rsaPublicKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *rsaPublicKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *rsaPublicKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *rsaPublicKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *rsaPublicKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case RSAEKey: + return h.e != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case RSANKey: + return h.n != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *rsaPublicKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`rsaPublicKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAEKey: + if h.e == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.e); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSANKey: + if h.n == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.n); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *rsaPublicKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *rsaPublicKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case RSAEKey: + if v, ok := value.([]byte); ok { + h.e = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAEKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case RSANKey: + if v, ok := value.([]byte); ok { + h.n = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSANKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *rsaPublicKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case RSAEKey: + k.e = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case RSANKey: + k.n = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *rsaPublicKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`rsaPublicKey.Clone: %w`, err) + } + return key, nil +} + +func (k *rsaPublicKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *rsaPublicKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *rsaPublicKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.e = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.n = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.RSA().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case RSAEKey: + if err := json.AssignNextBytesToken(&h.e, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAEKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case RSANKey: + if err := json.AssignNextBytesToken(&h.n, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSANKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.e == nil { + return fmt.Errorf(`required field e is missing`) + } + if h.n == nil { + return fmt.Errorf(`required field n is missing`) + } + return nil +} + +func (h rsaPublicKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 10) + data[KeyTypeKey] = jwa.RSA() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.e != nil { + data[RSAEKey] = h.e + fields = append(fields, RSAEKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.n != nil { + data[RSANKey] = h.n + fields = append(fields, RSANKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *rsaPublicKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 10+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.e != nil { + keys = append(keys, RSAEKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.n != nil { + keys = append(keys, RSANKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +type RSAPrivateKey interface { + Key + D() ([]byte, bool) + DP() ([]byte, bool) + DQ() ([]byte, bool) + E() ([]byte, bool) + N() ([]byte, bool) + P() ([]byte, bool) + Q() ([]byte, bool) + QI() ([]byte, bool) +} + +type rsaPrivateKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + d []byte + dp []byte + dq []byte + e []byte + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + n []byte + p []byte + q []byte + qi []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ RSAPrivateKey = &rsaPrivateKey{} +var _ Key = &rsaPrivateKey{} + +func newRSAPrivateKey() *rsaPrivateKey { + return &rsaPrivateKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h rsaPrivateKey) KeyType() jwa.KeyType { + return jwa.RSA() +} + +func (h rsaPrivateKey) rlock() { + h.mu.RLock() +} + +func (h rsaPrivateKey) runlock() { + h.mu.RUnlock() +} + +func (h rsaPrivateKey) IsPrivate() bool { + return true +} + +func (h *rsaPrivateKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *rsaPrivateKey) D() ([]byte, bool) { + if h.d != nil { + return h.d, true + } + return nil, false +} + +func (h *rsaPrivateKey) DP() ([]byte, bool) { + if h.dp != nil { + return h.dp, true + } + return nil, false +} + +func (h *rsaPrivateKey) DQ() ([]byte, bool) { + if h.dq != nil { + return h.dq, true + } + return nil, false +} + +func (h *rsaPrivateKey) E() ([]byte, bool) { + if h.e != nil { + return h.e, true + } + return nil, false +} + +func (h *rsaPrivateKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *rsaPrivateKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *rsaPrivateKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *rsaPrivateKey) N() ([]byte, bool) { + if h.n != nil { + return h.n, true + } + return nil, false +} + +func (h *rsaPrivateKey) P() ([]byte, bool) { + if h.p != nil { + return h.p, true + } + return nil, false +} + +func (h *rsaPrivateKey) Q() ([]byte, bool) { + if h.q != nil { + return h.q, true + } + return nil, false +} + +func (h *rsaPrivateKey) QI() ([]byte, bool) { + if h.qi != nil { + return h.qi, true + } + return nil, false +} + +func (h *rsaPrivateKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *rsaPrivateKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *rsaPrivateKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *rsaPrivateKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *rsaPrivateKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case RSADKey: + return h.d != nil + case RSADPKey: + return h.dp != nil + case RSADQKey: + return h.dq != nil + case RSAEKey: + return h.e != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case RSANKey: + return h.n != nil + case RSAPKey: + return h.p != nil + case RSAQKey: + return h.q != nil + case RSAQIKey: + return h.qi != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *rsaPrivateKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`rsaPrivateKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSADKey: + if h.d == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.d); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSADPKey: + if h.dp == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.dp); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSADQKey: + if h.dq == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.dq); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAEKey: + if h.e == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.e); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSANKey: + if h.n == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.n); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAPKey: + if h.p == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.p); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAQKey: + if h.q == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.q); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case RSAQIKey: + if h.qi == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.qi); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *rsaPrivateKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *rsaPrivateKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case RSADKey: + if v, ok := value.([]byte); ok { + h.d = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSADKey, value) + case RSADPKey: + if v, ok := value.([]byte); ok { + h.dp = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSADPKey, value) + case RSADQKey: + if v, ok := value.([]byte); ok { + h.dq = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSADQKey, value) + case RSAEKey: + if v, ok := value.([]byte); ok { + h.e = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAEKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case RSANKey: + if v, ok := value.([]byte); ok { + h.n = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSANKey, value) + case RSAPKey: + if v, ok := value.([]byte); ok { + h.p = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAPKey, value) + case RSAQKey: + if v, ok := value.([]byte); ok { + h.q = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAQKey, value) + case RSAQIKey: + if v, ok := value.([]byte); ok { + h.qi = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, RSAQIKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *rsaPrivateKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case RSADKey: + k.d = nil + case RSADPKey: + k.dp = nil + case RSADQKey: + k.dq = nil + case RSAEKey: + k.e = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case RSANKey: + k.n = nil + case RSAPKey: + k.p = nil + case RSAQKey: + k.q = nil + case RSAQIKey: + k.qi = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *rsaPrivateKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`rsaPrivateKey.Clone: %w`, err) + } + return key, nil +} + +func (k *rsaPrivateKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *rsaPrivateKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *rsaPrivateKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.d = nil + h.dp = nil + h.dq = nil + h.e = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.n = nil + h.p = nil + h.q = nil + h.qi = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.RSA().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case RSADKey: + if err := json.AssignNextBytesToken(&h.d, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSADKey, err) + } + case RSADPKey: + if err := json.AssignNextBytesToken(&h.dp, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSADPKey, err) + } + case RSADQKey: + if err := json.AssignNextBytesToken(&h.dq, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSADQKey, err) + } + case RSAEKey: + if err := json.AssignNextBytesToken(&h.e, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAEKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case RSANKey: + if err := json.AssignNextBytesToken(&h.n, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSANKey, err) + } + case RSAPKey: + if err := json.AssignNextBytesToken(&h.p, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAPKey, err) + } + case RSAQKey: + if err := json.AssignNextBytesToken(&h.q, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAQKey, err) + } + case RSAQIKey: + if err := json.AssignNextBytesToken(&h.qi, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, RSAQIKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.d == nil { + return fmt.Errorf(`required field d is missing`) + } + if h.e == nil { + return fmt.Errorf(`required field e is missing`) + } + if h.n == nil { + return fmt.Errorf(`required field n is missing`) + } + return nil +} + +func (h rsaPrivateKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 16) + data[KeyTypeKey] = jwa.RSA() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.d != nil { + data[RSADKey] = h.d + fields = append(fields, RSADKey) + } + if h.dp != nil { + data[RSADPKey] = h.dp + fields = append(fields, RSADPKey) + } + if h.dq != nil { + data[RSADQKey] = h.dq + fields = append(fields, RSADQKey) + } + if h.e != nil { + data[RSAEKey] = h.e + fields = append(fields, RSAEKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.n != nil { + data[RSANKey] = h.n + fields = append(fields, RSANKey) + } + if h.p != nil { + data[RSAPKey] = h.p + fields = append(fields, RSAPKey) + } + if h.q != nil { + data[RSAQKey] = h.q + fields = append(fields, RSAQKey) + } + if h.qi != nil { + data[RSAQIKey] = h.qi + fields = append(fields, RSAQIKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *rsaPrivateKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 16+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.d != nil { + keys = append(keys, RSADKey) + } + if h.dp != nil { + keys = append(keys, RSADPKey) + } + if h.dq != nil { + keys = append(keys, RSADQKey) + } + if h.e != nil { + keys = append(keys, RSAEKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.n != nil { + keys = append(keys, RSANKey) + } + if h.p != nil { + keys = append(keys, RSAPKey) + } + if h.q != nil { + keys = append(keys, RSAQKey) + } + if h.qi != nil { + keys = append(keys, RSAQIKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var rsaStandardFields KeyFilter + +func init() { + rsaStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, RSAEKey, RSANKey, RSADKey, RSADPKey, RSADQKey, RSAPKey, RSAQKey, RSAQIKey) +} + +// RSAStandardFieldsFilter returns a KeyFilter that filters out standard RSA fields. +func RSAStandardFieldsFilter() KeyFilter { + return rsaStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go new file mode 100644 index 0000000000..89d8646874 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go @@ -0,0 +1,311 @@ +package jwk + +import ( + "bytes" + "fmt" + "reflect" + "sort" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +const keysKey = `keys` // appease linter + +// NewSet creates and empty `jwk.Set` object +func NewSet() Set { + return &set{ + privateParams: make(map[string]any), + } +} + +func (s *set) Set(n string, v any) error { + s.mu.RLock() + defer s.mu.RUnlock() + + if n == keysKey { + vl, ok := v.([]Key) + if !ok { + return fmt.Errorf(`value for field "keys" must be []jwk.Key`) + } + s.keys = vl + return nil + } + + s.privateParams[n] = v + return nil +} + +func (s *set) Get(name string, dst any) error { + s.mu.RLock() + defer s.mu.RUnlock() + + v, ok := s.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value to dst: %w`, err) + } + return nil +} + +func (s *set) Key(idx int) (Key, bool) { + s.mu.RLock() + defer s.mu.RUnlock() + + if idx >= 0 && idx < len(s.keys) { + return s.keys[idx], true + } + return nil, false +} + +func (s *set) Len() int { + s.mu.RLock() + defer s.mu.RUnlock() + + return len(s.keys) +} + +// indexNL is Index(), but without the locking +func (s *set) indexNL(key Key) int { + for i, k := range s.keys { + if k == key { + return i + } + } + return -1 +} + +func (s *set) Index(key Key) int { + s.mu.RLock() + defer s.mu.RUnlock() + + return s.indexNL(key) +} + +func (s *set) AddKey(key Key) error { + s.mu.Lock() + defer s.mu.Unlock() + + if reflect.ValueOf(key).IsNil() { + panic("nil key") + } + + if i := s.indexNL(key); i > -1 { + return fmt.Errorf(`(jwk.Set).AddKey: key already exists`) + } + s.keys = append(s.keys, key) + return nil +} + +func (s *set) Remove(name string) error { + s.mu.Lock() + defer s.mu.Unlock() + + delete(s.privateParams, name) + return nil +} + +func (s *set) RemoveKey(key Key) error { + s.mu.Lock() + defer s.mu.Unlock() + + for i, k := range s.keys { + if k == key { + switch i { + case 0: + s.keys = s.keys[1:] + case len(s.keys) - 1: + s.keys = s.keys[:i] + default: + s.keys = append(s.keys[:i], s.keys[i+1:]...) + } + return nil + } + } + return fmt.Errorf(`(jwk.Set).RemoveKey: specified key does not exist in set`) +} + +func (s *set) Clear() error { + s.mu.Lock() + defer s.mu.Unlock() + + s.keys = nil + s.privateParams = make(map[string]any) + return nil +} + +func (s *set) Keys() []string { + ret := make([]string, len(s.privateParams)) + var i int + for k := range s.privateParams { + ret[i] = k + i++ + } + return ret +} + +func (s *set) MarshalJSON() ([]byte, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + + fields := []string{keysKey} + for k := range s.privateParams { + fields = append(fields, k) + } + sort.Strings(fields) + + buf.WriteByte(tokens.OpenCurlyBracket) + for i, field := range fields { + if i > 0 { + buf.WriteByte(tokens.Comma) + } + fmt.Fprintf(buf, `%q:`, field) + if field != keysKey { + if err := enc.Encode(s.privateParams[field]); err != nil { + return nil, fmt.Errorf(`failed to marshal field %q: %w`, field, err) + } + } else { + buf.WriteByte(tokens.OpenSquareBracket) + for j, k := range s.keys { + if j > 0 { + buf.WriteByte(tokens.Comma) + } + if err := enc.Encode(k); err != nil { + return nil, fmt.Errorf(`failed to marshal key #%d: %w`, i, err) + } + } + buf.WriteByte(tokens.CloseSquareBracket) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (s *set) UnmarshalJSON(data []byte) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.privateParams = make(map[string]any) + s.keys = nil + + var options []ParseOption + var ignoreParseError bool + if dc := s.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + options = append(options, withLocalRegistry(localReg)) + } + ignoreParseError = dc.IgnoreParseError() + } + + var sawKeysField bool + dec := json.NewDecoder(bytes.NewReader(data)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: + switch tok { + case "keys": + sawKeysField = true + var list []json.RawMessage + if err := dec.Decode(&list); err != nil { + return fmt.Errorf(`failed to decode "keys": %w`, err) + } + + for i, keysrc := range list { + key, err := ParseKey(keysrc, options...) + if err != nil { + if !ignoreParseError { + return fmt.Errorf(`failed to decode key #%d in "keys": %w`, i, err) + } + continue + } + s.keys = append(s.keys, key) + } + default: + var v any + if err := dec.Decode(&v); err != nil { + return fmt.Errorf(`failed to decode value for key %q: %w`, tok, err) + } + s.privateParams[tok] = v + } + } + } + + // This is really silly, but we can only detect the + // lack of the "keys" field after going through the + // entire object once + // Not checking for len(s.keys) == 0, because it could be + // an empty key set + if !sawKeysField { + key, err := ParseKey(data, options...) + if err != nil { + return fmt.Errorf(`failed to parse sole key in key set`) + } + s.keys = append(s.keys, key) + } + return nil +} + +func (s *set) LookupKeyID(kid string) (Key, bool) { + s.mu.RLock() + defer s.mu.RUnlock() + + for i := range s.Len() { + key, ok := s.Key(i) + if !ok { + return nil, false + } + gotkid, ok := key.KeyID() + if ok && gotkid == kid { + return key, true + } + } + return nil, false +} + +func (s *set) DecodeCtx() DecodeCtx { + s.mu.RLock() + defer s.mu.RUnlock() + return s.dc +} + +func (s *set) SetDecodeCtx(dc DecodeCtx) { + s.mu.Lock() + defer s.mu.Unlock() + s.dc = dc +} + +func (s *set) Clone() (Set, error) { + s2 := &set{} + + s.mu.RLock() + defer s.mu.RUnlock() + + s2.keys = make([]Key, len(s.keys)) + copy(s2.keys, s.keys) + return s2, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric.go new file mode 100644 index 0000000000..16427ff86f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric.go @@ -0,0 +1,105 @@ +package jwk + +import ( + "crypto" + "fmt" + "reflect" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + RegisterKeyExporter(jwa.OctetSeq(), KeyExportFunc(octetSeqToRaw)) +} + +func (k *symmetricKey) Import(rawKey []byte) error { + k.mu.Lock() + defer k.mu.Unlock() + + if len(rawKey) == 0 { + return fmt.Errorf(`non-empty []byte key required`) + } + + k.octets = rawKey + + return nil +} + +var symmetricConvertibleKeys = []reflect.Type{ + reflect.TypeOf((*SymmetricKey)(nil)).Elem(), +} + +func octetSeqToRaw(key Key, hint any) (any, error) { + extracted, err := extractEmbeddedKey(key, symmetricConvertibleKeys) + if err != nil { + return nil, fmt.Errorf(`failed to extract embedded key: %w`, err) + } + + switch key := extracted.(type) { + case SymmetricKey: + switch hint.(type) { + case *[]byte, *any: + default: + return nil, fmt.Errorf(`invalid destination object type %T for symmetric key: %w`, hint, ContinueError()) + } + + locker, ok := key.(rlocker) + if ok { + locker.rlock() + defer locker.runlock() + } + + ooctets, ok := key.Octets() + if !ok { + return nil, fmt.Errorf(`jwk.SymmetricKey: missing "k" field`) + } + + octets := make([]byte, len(ooctets)) + copy(octets, ooctets) + return octets, nil + default: + return nil, ContinueError() + } +} + +// Thumbprint returns the JWK thumbprint using the indicated +// hashing algorithm, according to RFC 7638 +func (k *symmetricKey) Thumbprint(hash crypto.Hash) ([]byte, error) { + k.mu.RLock() + defer k.mu.RUnlock() + var octets []byte + if err := Export(k, &octets); err != nil { + return nil, fmt.Errorf(`failed to export symmetric key: %w`, err) + } + + h := hash.New() + fmt.Fprint(h, `{"k":"`) + fmt.Fprint(h, base64.EncodeToString(octets)) + fmt.Fprint(h, `","kty":"oct"}`) + return h.Sum(nil), nil +} + +func (k *symmetricKey) PublicKey() (Key, error) { + newKey := newSymmetricKey() + + for _, key := range k.Keys() { + var v any + if err := k.Get(key, &v); err != nil { + return nil, fmt.Errorf(`failed to get field %q: %w`, key, err) + } + + if err := newKey.Set(key, v); err != nil { + return nil, fmt.Errorf(`failed to set field %q: %w`, key, err) + } + } + return newKey, nil +} + +func (k *symmetricKey) Validate() error { + octets, ok := k.Octets() + if !ok || len(octets) == 0 { + return NewKeyValidationError(fmt.Errorf(`jwk.SymmetricKey: missing "k" field`)) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric_gen.go new file mode 100644 index 0000000000..bfd2f8497d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/symmetric_gen.go @@ -0,0 +1,620 @@ +// Code generated by tools/cmd/genjwk/main.go. DO NOT EDIT. + +package jwk + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +const ( + SymmetricOctetsKey = "k" +) + +type SymmetricKey interface { + Key + Octets() ([]byte, bool) +} + +type symmetricKey struct { + algorithm *jwa.KeyAlgorithm // https://tools.ietf.org/html/rfc7517#section-4.4 + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + keyOps *KeyOperationList // https://tools.ietf.org/html/rfc7517#section-4.3 + keyUsage *string // https://tools.ietf.org/html/rfc7517#section-4.2 + octets []byte + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc json.DecodeCtx +} + +var _ SymmetricKey = &symmetricKey{} +var _ Key = &symmetricKey{} + +func newSymmetricKey() *symmetricKey { + return &symmetricKey{ + mu: &sync.RWMutex{}, + privateParams: make(map[string]any), + } +} + +func (h symmetricKey) KeyType() jwa.KeyType { + return jwa.OctetSeq() +} + +func (h symmetricKey) rlock() { + h.mu.RLock() +} + +func (h symmetricKey) runlock() { + h.mu.RUnlock() +} + +func (h *symmetricKey) Algorithm() (jwa.KeyAlgorithm, bool) { + if h.algorithm != nil { + return *(h.algorithm), true + } + return nil, false +} + +func (h *symmetricKey) KeyID() (string, bool) { + if h.keyID != nil { + return *(h.keyID), true + } + return "", false +} + +func (h *symmetricKey) KeyOps() (KeyOperationList, bool) { + if h.keyOps != nil { + return *(h.keyOps), true + } + return nil, false +} + +func (h *symmetricKey) KeyUsage() (string, bool) { + if h.keyUsage != nil { + return *(h.keyUsage), true + } + return "", false +} + +func (h *symmetricKey) Octets() ([]byte, bool) { + if h.octets != nil { + return h.octets, true + } + return nil, false +} + +func (h *symmetricKey) X509CertChain() (*cert.Chain, bool) { + return h.x509CertChain, true +} + +func (h *symmetricKey) X509CertThumbprint() (string, bool) { + if h.x509CertThumbprint != nil { + return *(h.x509CertThumbprint), true + } + return "", false +} + +func (h *symmetricKey) X509CertThumbprintS256() (string, bool) { + if h.x509CertThumbprintS256 != nil { + return *(h.x509CertThumbprintS256), true + } + return "", false +} + +func (h *symmetricKey) X509URL() (string, bool) { + if h.x509URL != nil { + return *(h.x509URL), true + } + return "", false +} + +func (h *symmetricKey) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + return true + case AlgorithmKey: + return h.algorithm != nil + case KeyIDKey: + return h.keyID != nil + case KeyOpsKey: + return h.keyOps != nil + case KeyUsageKey: + return h.keyUsage != nil + case SymmetricOctetsKey: + return h.octets != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *symmetricKey) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case KeyTypeKey: + if err := blackmagic.AssignIfCompatible(dst, h.KeyType()); err != nil { + return fmt.Errorf(`symmetricKey.Get: failed to assign value for field %q to destination object: %w`, name, err) + } + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyOpsKey: + if h.keyOps == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyOps)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyUsageKey: + if h.keyUsage == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyUsage)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case SymmetricOctetsKey: + if h.octets == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.octets); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *symmetricKey) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *symmetricKey) setNoLock(name string, value any) error { + switch name { + case "kty": + return nil + case AlgorithmKey: + switch v := value.(type) { + case string, jwa.SignatureAlgorithm, jwa.KeyEncryptionAlgorithm, jwa.ContentEncryptionAlgorithm: + tmp, err := jwa.KeyAlgorithmFrom(v) + if err != nil { + return fmt.Errorf(`invalid algorithm for %q key: %w`, AlgorithmKey, err) + } + h.algorithm = &tmp + default: + return fmt.Errorf(`invalid type for %q key: %T`, AlgorithmKey, value) + } + return nil + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case KeyOpsKey: + var acceptor KeyOperationList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, KeyOpsKey, err) + } + h.keyOps = &acceptor + return nil + case KeyUsageKey: + switch v := value.(type) { + case KeyUsageType: + switch v { + case ForSignature, ForEncryption: + tmp := v.String() + h.keyUsage = &tmp + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case string: + h.keyUsage = &v + default: + return fmt.Errorf(`invalid key usage type %s`, v) + } + case SymmetricOctetsKey: + if v, ok := value.([]byte); ok { + h.octets = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, SymmetricOctetsKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (k *symmetricKey) Remove(key string) error { + k.mu.Lock() + defer k.mu.Unlock() + switch key { + case AlgorithmKey: + k.algorithm = nil + case KeyIDKey: + k.keyID = nil + case KeyOpsKey: + k.keyOps = nil + case KeyUsageKey: + k.keyUsage = nil + case SymmetricOctetsKey: + k.octets = nil + case X509CertChainKey: + k.x509CertChain = nil + case X509CertThumbprintKey: + k.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + k.x509CertThumbprintS256 = nil + case X509URLKey: + k.x509URL = nil + default: + delete(k.privateParams, key) + } + return nil +} + +func (k *symmetricKey) Clone() (Key, error) { + key, err := cloneKey(k) + if err != nil { + return nil, fmt.Errorf(`symmetricKey.Clone: %w`, err) + } + return key, nil +} + +func (k *symmetricKey) DecodeCtx() json.DecodeCtx { + k.mu.RLock() + defer k.mu.RUnlock() + return k.dc +} + +func (k *symmetricKey) SetDecodeCtx(dc json.DecodeCtx) { + k.mu.Lock() + defer k.mu.Unlock() + k.dc = dc +} + +func (h *symmetricKey) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.algorithm = nil + h.keyID = nil + h.keyOps = nil + h.keyUsage = nil + h.octets = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case KeyTypeKey: + val, err := json.ReadNextStringToken(dec) + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + if val != jwa.OctetSeq().String() { + return fmt.Errorf(`invalid kty value for RSAPublicKey (%s)`, val) + } + case AlgorithmKey: + var s string + if err := dec.Decode(&s); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + alg, err := jwa.KeyAlgorithmFrom(s) + if err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &alg + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case KeyOpsKey: + var decoded KeyOperationList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyOpsKey, err) + } + h.keyOps = &decoded + case KeyUsageKey: + if err := json.AssignNextStringToken(&h.keyUsage, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyUsageKey, err) + } + case SymmetricOctetsKey: + if err := json.AssignNextBytesToken(&h.octets, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, SymmetricOctetsKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + if dc := h.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + h.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + if h.octets == nil { + return fmt.Errorf(`required field k is missing`) + } + return nil +} + +func (h symmetricKey) MarshalJSON() ([]byte, error) { + data := make(map[string]any) + fields := make([]string, 0, 9) + data[KeyTypeKey] = jwa.OctetSeq() + fields = append(fields, KeyTypeKey) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + fields = append(fields, AlgorithmKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + fields = append(fields, KeyIDKey) + } + if h.keyOps != nil { + data[KeyOpsKey] = *(h.keyOps) + fields = append(fields, KeyOpsKey) + } + if h.keyUsage != nil { + data[KeyUsageKey] = *(h.keyUsage) + fields = append(fields, KeyUsageKey) + } + if h.octets != nil { + data[SymmetricOctetsKey] = h.octets + fields = append(fields, SymmetricOctetsKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + fields = append(fields, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + fields = append(fields, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + fields = append(fields, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + fields = append(fields, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + fields = append(fields, k) + } + + sort.Strings(fields) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + enc := json.NewEncoder(buf) + for i, f := range fields { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(f) + buf.WriteString(`":`) + v := data[f] + switch v := v.(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, f, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (h *symmetricKey) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 9+len(h.privateParams)) + keys = append(keys, KeyTypeKey) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.keyOps != nil { + keys = append(keys, KeyOpsKey) + } + if h.keyUsage != nil { + keys = append(keys, KeyUsageKey) + } + if h.octets != nil { + keys = append(keys, SymmetricOctetsKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +var symmetricStandardFields KeyFilter + +func init() { + symmetricStandardFields = NewFieldNameFilter(KeyTypeKey, KeyUsageKey, KeyOpsKey, AlgorithmKey, KeyIDKey, X509URLKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, SymmetricOctetsKey) +} + +// SymmetricStandardFieldsFilter returns a KeyFilter that filters out standard Symmetric fields. +func SymmetricStandardFieldsFilter() KeyFilter { + return symmetricStandardFields +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/usage.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/usage.go new file mode 100644 index 0000000000..ed724153b8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/usage.go @@ -0,0 +1,74 @@ +package jwk + +import ( + "fmt" + "sync" + "sync/atomic" +) + +var strictKeyUsage = atomic.Bool{} +var keyUsageNames = map[string]struct{}{} +var muKeyUsageName sync.RWMutex + +// RegisterKeyUsage registers a possible value that can be used for KeyUsageType. +// Normally, key usage (or the "use" field in a JWK) is either "sig" or "enc", +// but other values may be used. +// +// While this module only works with "sig" and "enc", it is possible that +// systems choose to use other values. This function allows users to register +// new values to be accepted as valid key usage types. Values are case sensitive. +// +// Furthermore, the check against registered values can be completely turned off +// by setting the global option `jwk.WithStrictKeyUsage(false)`. +func RegisterKeyUsage(v string) { + muKeyUsageName.Lock() + defer muKeyUsageName.Unlock() + keyUsageNames[v] = struct{}{} +} + +func UnregisterKeyUsage(v string) { + muKeyUsageName.Lock() + defer muKeyUsageName.Unlock() + delete(keyUsageNames, v) +} + +func init() { + strictKeyUsage.Store(true) + RegisterKeyUsage("sig") + RegisterKeyUsage("enc") +} + +func isValidUsage(v string) bool { + // This function can return true if strictKeyUsage is false + if !strictKeyUsage.Load() { + return true + } + + muKeyUsageName.RLock() + defer muKeyUsageName.RUnlock() + _, ok := keyUsageNames[v] + return ok +} + +func (k KeyUsageType) String() string { + return string(k) +} + +func (k *KeyUsageType) Accept(v any) error { + switch v := v.(type) { + case KeyUsageType: + if !isValidUsage(v.String()) { + return fmt.Errorf("invalid key usage type: %q", v) + } + *k = v + return nil + case string: + if !isValidUsage(v) { + return fmt.Errorf("invalid key usage type: %q", v) + } + *k = KeyUsageType(v) + return nil + } + + return fmt.Errorf("invalid Go type for key usage type: %T", v) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/whitelist.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/whitelist.go new file mode 100644 index 0000000000..0b0df701ae --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/whitelist.go @@ -0,0 +1,38 @@ +package jwk + +import "github.com/lestrrat-go/httprc/v3" + +type Whitelist = httprc.Whitelist +type WhitelistFunc = httprc.WhitelistFunc + +// InsecureWhitelist is an alias to httprc.InsecureWhitelist. Use +// functions in the `httprc` package to interact with this type. +type InsecureWhitelist = httprc.InsecureWhitelist + +func NewInsecureWhitelist() InsecureWhitelist { + return httprc.NewInsecureWhitelist() +} + +// BlockAllWhitelist is an alias to httprc.BlockAllWhitelist. Use +// functions in the `httprc` package to interact with this type. +type BlockAllWhitelist = httprc.BlockAllWhitelist + +func NewBlockAllWhitelist() BlockAllWhitelist { + return httprc.NewBlockAllWhitelist() +} + +// RegexpWhitelist is an alias to httprc.RegexpWhitelist. Use +// functions in the `httprc` package to interact with this type. +type RegexpWhitelist = httprc.RegexpWhitelist + +func NewRegexpWhitelist() *RegexpWhitelist { + return httprc.NewRegexpWhitelist() +} + +// MapWhitelist is an alias to httprc.MapWhitelist. Use +// functions in the `httprc` package to interact with this type. +type MapWhitelist = httprc.MapWhitelist + +func NewMapWhitelist() MapWhitelist { + return httprc.NewMapWhitelist() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwk/x509.go b/vendor/github.com/lestrrat-go/jwx/v3/jwk/x509.go new file mode 100644 index 0000000000..c0a7c4c4d9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwk/x509.go @@ -0,0 +1,249 @@ +package jwk + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/jwk/jwkbb" +) + +// PEMDecoder is an interface to describe an object that can decode +// a key from PEM encoded ASN.1 DER format. +// +// A PEMDecoder can be specified as an option to `jwk.Parse()` or `jwk.ParseKey()` +// along with the `jwk.WithPEM()` option. +type PEMDecoder interface { + Decode([]byte) (any, []byte, error) +} + +// PEMEncoder is an interface to describe an object that can encode +// a key into PEM encoded ASN.1 DER format. +// +// `jwk.Key` instances do not implement a way to encode themselves into +// PEM format. Normally you can just use `jwk.EncodePEM()` to do this, but +// this interface allows you to generalize the encoding process by +// abstracting the `jwk.EncodePEM()` function using `jwk.PEMEncodeFunc` +// along with alternate implementations, should you need them. +type PEMEncoder interface { + Encode(any) (string, []byte, error) +} + +type PEMEncodeFunc func(any) (string, []byte, error) + +func (f PEMEncodeFunc) Encode(v any) (string, []byte, error) { + return f(v) +} + +func encodeX509(v any) (string, []byte, error) { + // we can't import jwk, so just use the interface + if key, ok := v.(Key); ok { + var raw any + if err := Export(key, &raw); err != nil { + return "", nil, fmt.Errorf(`failed to get raw key out of %T: %w`, key, err) + } + + v = raw + } + + // Try to convert it into a certificate + switch v := v.(type) { + case *rsa.PrivateKey: + return pmRSAPrivateKey, x509.MarshalPKCS1PrivateKey(v), nil + case *ecdsa.PrivateKey: + marshaled, err := x509.MarshalECPrivateKey(v) + if err != nil { + return "", nil, err + } + return pmECPrivateKey, marshaled, nil + case ed25519.PrivateKey: + marshaled, err := x509.MarshalPKCS8PrivateKey(v) + if err != nil { + return "", nil, err + } + return pmPrivateKey, marshaled, nil + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: + marshaled, err := x509.MarshalPKIXPublicKey(v) + if err != nil { + return "", nil, err + } + return pmPublicKey, marshaled, nil + default: + return "", nil, fmt.Errorf(`unsupported type %T for ASN.1 DER encoding`, v) + } +} + +// EncodePEM encodes the key into a PEM encoded ASN.1 DER format. +// The key can be a jwk.Key or a raw key instance, but it must be one of +// the types supported by `x509` package. +// +// Internally, it uses the same routine as `jwk.EncodeX509()`, and therefore +// the same caveats apply +func EncodePEM(v any) ([]byte, error) { + typ, marshaled, err := encodeX509(v) + if err != nil { + return nil, fmt.Errorf(`failed to encode key in x509: %w`, err) + } + + block := &pem.Block{ + Type: typ, + Bytes: marshaled, + } + return pem.EncodeToMemory(block), nil +} + +const ( + pmPrivateKey = `PRIVATE KEY` + pmPublicKey = `PUBLIC KEY` + pmECPrivateKey = `EC PRIVATE KEY` + pmRSAPublicKey = `RSA PUBLIC KEY` + pmRSAPrivateKey = `RSA PRIVATE KEY` +) + +// NewPEMDecoder returns a PEMDecoder that decodes keys in PEM encoded ASN.1 DER format. +// You can use it as argument to `jwk.WithPEMDecoder()` option. +// +// The use of this function is planned to be deprecated. The plan is to replace the +// `jwk.WithPEMDecoder()` option with globally available custom X509 decoders which +// can be registered via `jwk.RegisterX509Decoder()` function. +func NewPEMDecoder() PEMDecoder { + return pemDecoder{} +} + +type pemDecoder struct{} + +// DecodePEM decodes a key in PEM encoded ASN.1 DER format. +// and returns a raw key. +func (pemDecoder) Decode(src []byte) (any, []byte, error) { + block, rest := pem.Decode(src) + if block == nil { + return nil, rest, fmt.Errorf(`failed to decode PEM data`) + } + var ret any + if err := jwkbb.DecodeX509(&ret, block); err != nil { + return nil, rest, err + } + return ret, rest, nil +} + +// X509Decoder is an interface that describes an object that can decode +// a PEM encoded ASN.1 DER format into a specific type of key. +// +// This interface is experimental, and may change in the future. +type X509Decoder interface { + // DecodeX509 decodes the given PEM block into the destination object. + // The destination object must be a pointer to a type that can hold the + // decoded key, such as *rsa.PrivateKey, *ecdsa.PrivateKey, etc. + DecodeX509(dst any, block *pem.Block) error +} + +// X509DecodeFunc is a function type that implements the X509Decoder interface. +// It allows you to create a custom X509Decoder by providing a function +// that takes a destination and a PEM block, and returns an error if the decoding fails. +// +// This interface is experimental, and may change in the future. +type X509DecodeFunc func(dst any, block *pem.Block) error + +func (f X509DecodeFunc) DecodeX509(dst any, block *pem.Block) error { + return f(dst, block) +} + +var muX509Decoders sync.Mutex +var x509Decoders = map[any]int{} +var x509DecoderList = []X509Decoder{} + +type identDefaultX509Decoder struct{} + +func init() { + RegisterX509Decoder(identDefaultX509Decoder{}, X509DecodeFunc(jwkbb.DecodeX509)) +} + +// RegisterX509Decoder registers a new X509Decoder that can decode PEM encoded ASN.1 DER format. +// Because the decoder could be non-comparable, you must provide an identifier that can be used +// as a map key to identify the decoder. +// +// This function is experimental, and may change in the future. +func RegisterX509Decoder(ident any, decoder X509Decoder) { + if decoder == nil { + panic(`jwk.RegisterX509Decoder: decoder cannot be nil`) + } + + muX509Decoders.Lock() + defer muX509Decoders.Unlock() + if _, ok := x509Decoders[ident]; ok { + return // already registered + } + + x509Decoders[ident] = len(x509DecoderList) + x509DecoderList = append(x509DecoderList, decoder) +} + +// UnregisterX509Decoder unregisters the X509Decoder identified by the given identifier. +// If the identifier is not registered, it does nothing. +// +// This function is experimental, and may change in the future. +func UnregisterX509Decoder(ident any) { + muX509Decoders.Lock() + defer muX509Decoders.Unlock() + idx, ok := x509Decoders[ident] + if !ok { + return // not registered + } + + delete(x509Decoders, ident) + + l := len(x509DecoderList) + switch idx { + case l - 1: + // if the last element, just truncate the slice + x509DecoderList = x509DecoderList[:l-1] + case 0: + // if the first element, just shift the slice + x509DecoderList = x509DecoderList[1:] + default: + // if the element is in the middle, remove it by slicing + // and appending the two slices together + x509DecoderList = append(x509DecoderList[:idx], x509DecoderList[idx+1:]...) + } +} + +// decodeX509 decodes a PEM encoded ASN.1 DER format into the given destination. +// It tries all registered X509 decoders until one of them succeeds. +// If no decoder can handle the PEM block, it returns an error. +func decodeX509(dst any, src []byte) error { + block, _ := pem.Decode(src) + if block == nil { + return fmt.Errorf(`failed to decode PEM data`) + } + + var errs []error + for _, d := range x509DecoderList { + if err := d.DecodeX509(dst, block); err != nil { + errs = append(errs, err) + continue + } + // successfully decoded + return nil + } + + return fmt.Errorf(`failed to decode X509 data using any of the decoders: %w`, errors.Join(errs...)) +} + +func decodeX509WithPEMDEcoder(dst any, src []byte, decoder PEMDecoder) error { + ret, _, err := decoder.Decode(src) + if err != nil { + return fmt.Errorf(`failed to decode PEM data: %w`, err) + } + + if err := blackmagic.AssignIfCompatible(dst, ret); err != nil { + return fmt.Errorf(`failed to assign decoded key to destination: %w`, err) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/BUILD.bazel new file mode 100644 index 0000000000..920d3f87b1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/BUILD.bazel @@ -0,0 +1,76 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jws", + srcs = [ + "errors.go", + "filter.go", + "headers.go", + "headers_gen.go", + "interface.go", + "io.go", + "jws.go", + "key_provider.go", + "legacy.go", + "message.go", + "options.go", + "options_gen.go", + "signer.go", + "sign_context.go", + "signature_builder.go", + "verifier.go", + "verify_context.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jws", + visibility = ["//visibility:public"], + deps = [ + "//cert", + "//internal/base64", + "//internal/ecutil", + "//internal/json", + "//internal/jwxio", + "//internal/tokens", + "//internal/keyconv", + "//internal/pool", + "//jwa", + "//jwk", + "//jws/internal/keytype", + "//jws/jwsbb", + "//jws/legacy", + "//transform", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jws_test", + srcs = [ + "es256k_test.go", + "filter_test.go", + "headers_test.go", + "jws_test.go", + "message_test.go", + "options_gen_test.go", + "signer_test.go", + ], + embed = [":jws"], + deps = [ + "//cert", + "//internal/base64", + "//internal/ecutil", + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwk", + "//jwt", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jws", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jws/README.md new file mode 100644 index 0000000000..29ca7218e4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/README.md @@ -0,0 +1,111 @@ +# JWS [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jws.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jws) + +Package jws implements JWS as described in [RFC7515](https://tools.ietf.org/html/rfc7515) and [RFC7797](https://tools.ietf.org/html/rfc7797) + +* Parse and generate compact or JSON serializations +* Sign and verify arbitrary payload +* Use any of the keys supported in [github.com/lestrrat-go/jwx/v3/jwk](../jwk) +* Add arbitrary fields in the JWS object +* Ability to add/replace existing signature methods +* Respect "b64" settings for RFC7797 + +How-to style documentation can be found in the [docs directory](../docs). + +Examples are located in the examples directory ([jws_example_test.go](../examples/jws_example_test.go)) + +Supported signature algorithms: + +| Algorithm | Supported? | Constant in [jwa](../jwa) | +|:----------------------------------------|:-----------|:-------------------------| +| HMAC using SHA-256 | YES | jwa.HS256 | +| HMAC using SHA-384 | YES | jwa.HS384 | +| HMAC using SHA-512 | YES | jwa.HS512 | +| RSASSA-PKCS-v1.5 using SHA-256 | YES | jwa.RS256 | +| RSASSA-PKCS-v1.5 using SHA-384 | YES | jwa.RS384 | +| RSASSA-PKCS-v1.5 using SHA-512 | YES | jwa.RS512 | +| ECDSA using P-256 and SHA-256 | YES | jwa.ES256 | +| ECDSA using P-384 and SHA-384 | YES | jwa.ES384 | +| ECDSA using P-521 and SHA-512 | YES | jwa.ES512 | +| ECDSA using secp256k1 and SHA-256 (2) | YES | jwa.ES256K | +| RSASSA-PSS using SHA256 and MGF1-SHA256 | YES | jwa.PS256 | +| RSASSA-PSS using SHA384 and MGF1-SHA384 | YES | jwa.PS384 | +| RSASSA-PSS using SHA512 and MGF1-SHA512 | YES | jwa.PS512 | +| EdDSA (1) | YES | jwa.EdDSA | + +* Note 1: Experimental +* Note 2: Experimental, and must be toggled using `-tags jwx_es256k` build tag + +# SYNOPSIS + +## Sign and verify arbitrary data + +```go +import( + "crypto/rand" + "crypto/rsa" + "log" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws" +) + +func main() { + privkey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Printf("failed to generate private key: %s", err) + return + } + + buf, err := jws.Sign([]byte("Lorem ipsum"), jws.WithKey(jwa.RS256, privkey)) + if err != nil { + log.Printf("failed to created JWS message: %s", err) + return + } + + // When you receive a JWS message, you can verify the signature + // and grab the payload sent in the message in one go: + verified, err := jws.Verify(buf, jws.WithKey(jwa.RS256, &privkey.PublicKey)) + if err != nil { + log.Printf("failed to verify message: %s", err) + return + } + + log.Printf("signed message verified! -> %s", verified) +} +``` + +## Programmatically manipulate `jws.Message` + +```go +func ExampleMessage() { + // initialization for the following variables have been omitted. + // please see jws_example_test.go for details + var decodedPayload, decodedSig1, decodedSig2 []byte + var public1, protected1, public2, protected2 jws.Header + + // Construct a message. DO NOT use values that are base64 encoded + m := jws.NewMessage(). + SetPayload(decodedPayload). + AppendSignature( + jws.NewSignature(). + SetSignature(decodedSig1). + SetProtectedHeaders(public1). + SetPublicHeaders(protected1), + ). + AppendSignature( + jws.NewSignature(). + SetSignature(decodedSig2). + SetProtectedHeaders(public2). + SetPublicHeaders(protected2), + ) + + buf, err := json.MarshalIndent(m, "", " ") + if err != nil { + fmt.Printf("%s\n", err) + return + } + + _ = buf +} +``` + diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/errors.go new file mode 100644 index 0000000000..d5e1762a6a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/errors.go @@ -0,0 +1,112 @@ +package jws + +import ( + "fmt" +) + +type signError struct { + error +} + +var errDefaultSignError = signerr(`unknown error`) + +// SignError returns an error that can be passed to `errors.Is` to check if the error is a sign error. +func SignError() error { + return errDefaultSignError +} + +func (e signError) Unwrap() error { + return e.error +} + +func (signError) Is(err error) bool { + _, ok := err.(signError) + return ok +} + +func signerr(f string, args ...any) error { + return signError{fmt.Errorf(`jws.Sign: `+f, args...)} +} + +// This error is returned when jws.Verify fails, but note that there's another type of +// message that can be returned by jws.Verify, which is `errVerification`. +type verifyError struct { + error +} + +var errDefaultVerifyError = verifyerr(`unknown error`) + +// VerifyError returns an error that can be passed to `errors.Is` to check if the error is a verify error. +func VerifyError() error { + return errDefaultVerifyError +} + +func (e verifyError) Unwrap() error { + return e.error +} + +func (verifyError) Is(err error) bool { + _, ok := err.(verifyError) + return ok +} + +func verifyerr(f string, args ...any) error { + return verifyError{fmt.Errorf(`jws.Verify: `+f, args...)} +} + +// verificationError is returned when the actual _verification_ of the key/payload fails. +type verificationError struct { + error +} + +var errDefaultVerificationError = verificationError{fmt.Errorf(`unknown verification error`)} + +// VerificationError returns an error that can be passed to `errors.Is` to check if the error is a verification error. +func VerificationError() error { + return errDefaultVerificationError +} + +func (e verificationError) Unwrap() error { + return e.error +} + +func (verificationError) Is(err error) bool { + _, ok := err.(verificationError) + return ok +} + +type parseError struct { + error +} + +var errDefaultParseError = parseerr(`unknown error`) + +// ParseError returns an error that can be passed to `errors.Is` to check if the error is a parse error. +func ParseError() error { + return errDefaultParseError +} + +func (e parseError) Unwrap() error { + return e.error +} + +func (parseError) Is(err error) bool { + _, ok := err.(parseError) + return ok +} + +func bparseerr(prefix string, f string, args ...any) error { + return parseError{fmt.Errorf(prefix+": "+f, args...)} +} + +func parseerr(f string, args ...any) error { + return bparseerr(`jws.Parse`, f, args...) +} + +func sparseerr(f string, args ...any) error { + return bparseerr(`jws.ParseString`, f, args...) +} + +func rparseerr(f string, args ...any) error { + return bparseerr(`jws.ParseReader`, f, args...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/es256k.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/es256k.go new file mode 100644 index 0000000000..ff5a1d8f78 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/es256k.go @@ -0,0 +1,12 @@ +//go:build jwx_es256k +// +build jwx_es256k + +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + addAlgorithmForKeyType(jwa.EC(), jwa.ES256K()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/filter.go new file mode 100644 index 0000000000..9351ab870b --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/filter.go @@ -0,0 +1,36 @@ +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// HeaderFilter is an interface that allows users to filter JWS header fields. +// It provides two methods: Filter and Reject; Filter returns a new header with only +// the fields that match the filter criteria, while Reject returns a new header with +// only the fields that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type HeaderFilter interface { + Filter(header Headers) (Headers, error) + Reject(header Headers) (Headers, error) +} + +// StandardHeadersFilter returns a HeaderFilter that filters out standard JWS header fields. +// +// You can use this filter to create headers that either only have standard fields +// or only custom fields. +// +// If you need to configure the filter more precisely, consider +// using the HeaderNameFilter directly. +func StandardHeadersFilter() HeaderFilter { + return stdHeadersFilter +} + +var stdHeadersFilter = NewHeaderNameFilter(stdHeaderNames...) + +// NewHeaderNameFilter creates a new HeaderNameFilter with the specified field names. +func NewHeaderNameFilter(names ...string) HeaderFilter { + return transform.NewNameBasedFilter[Headers](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/headers.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers.go new file mode 100644 index 0000000000..45f8e8959e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers.go @@ -0,0 +1,52 @@ +package jws + +import ( + "fmt" +) + +func (h *stdHeaders) Copy(dst Headers) error { + for _, k := range h.Keys() { + var v any + if err := h.Get(k, &v); err != nil { + return fmt.Errorf(`failed to get header %q: %w`, k, err) + } + if err := dst.Set(k, v); err != nil { + return fmt.Errorf(`failed to set header %q: %w`, k, err) + } + } + return nil +} + +// mergeHeaders merges two headers, and works even if the first Header +// object is nil. This is not exported because ATM it felt like this +// function is not frequently used, and MergeHeaders seemed a clunky name +func mergeHeaders(h1, h2 Headers) (Headers, error) { + h3 := NewHeaders() + + if h1 != nil { + if err := h1.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from first Header: %w`, err) + } + } + + if h2 != nil { + if err := h2.Copy(h3); err != nil { + return nil, fmt.Errorf(`failed to copy headers from second Header: %w`, err) + } + } + + return h3, nil +} + +func (h *stdHeaders) Merge(h2 Headers) (Headers, error) { + return mergeHeaders(h, h2) +} + +// Clone creates a deep copy of the header +func (h *stdHeaders) Clone() (Headers, error) { + dst := NewHeaders() + if err := h.Copy(dst); err != nil { + return nil, fmt.Errorf(`failed to copy header: %w`, err) + } + return dst, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/headers_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers_gen.go new file mode 100644 index 0000000000..8465eda2b1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/headers_gen.go @@ -0,0 +1,704 @@ +// Code generated by tools/cmd/genjws/main.go. DO NOT EDIT. + +package jws + +import ( + "bytes" + "fmt" + "sort" + "sync" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/cert" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +const ( + AlgorithmKey = "alg" + ContentTypeKey = "cty" + CriticalKey = "crit" + JWKKey = "jwk" + JWKSetURLKey = "jku" + KeyIDKey = "kid" + TypeKey = "typ" + X509CertChainKey = "x5c" + X509CertThumbprintKey = "x5t" + X509CertThumbprintS256Key = "x5t#S256" + X509URLKey = "x5u" +) + +// Headers describe a standard JWS Header set. It is part of the JWS message +// and is used to represet both Public or Protected headers, which in turn +// can be found in each Signature object. If you are not sure how this works, +// it is strongly recommended that you read RFC7515, especially the section +// that describes the full JSON serialization format of JWS messages. +// +// In most cases, you likely want to use the protected headers, as this is part of the signed content. +type Headers interface { + Algorithm() (jwa.SignatureAlgorithm, bool) + ContentType() (string, bool) + Critical() ([]string, bool) + JWK() (jwk.Key, bool) + JWKSetURL() (string, bool) + KeyID() (string, bool) + Type() (string, bool) + X509CertChain() (*cert.Chain, bool) + X509CertThumbprint() (string, bool) + X509CertThumbprintS256() (string, bool) + X509URL() (string, bool) + Copy(Headers) error + Merge(Headers) (Headers, error) + Clone() (Headers, error) + // Get is used to extract the value of any field, including non-standard fields, out of the header. + // + // The first argument is the name of the field. The second argument is a pointer + // to a variable that will receive the value of the field. The method returns + // an error if the field does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + Get(string, any) error + Set(string, any) error + Remove(string) error + // Has returns true if the specified header has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + Keys() []string +} + +// stdHeaderNames is a list of all standard header names defined in the JWS specification. +var stdHeaderNames = []string{AlgorithmKey, ContentTypeKey, CriticalKey, JWKKey, JWKSetURLKey, KeyIDKey, TypeKey, X509CertChainKey, X509CertThumbprintKey, X509CertThumbprintS256Key, X509URLKey} + +type stdHeaders struct { + algorithm *jwa.SignatureAlgorithm // https://tools.ietf.org/html/rfc7515#section-4.1.1 + contentType *string // https://tools.ietf.org/html/rfc7515#section-4.1.10 + critical []string // https://tools.ietf.org/html/rfc7515#section-4.1.11 + jwk jwk.Key // https://tools.ietf.org/html/rfc7515#section-4.1.3 + jwkSetURL *string // https://tools.ietf.org/html/rfc7515#section-4.1.2 + keyID *string // https://tools.ietf.org/html/rfc7515#section-4.1.4 + typ *string // https://tools.ietf.org/html/rfc7515#section-4.1.9 + x509CertChain *cert.Chain // https://tools.ietf.org/html/rfc7515#section-4.1.6 + x509CertThumbprint *string // https://tools.ietf.org/html/rfc7515#section-4.1.7 + x509CertThumbprintS256 *string // https://tools.ietf.org/html/rfc7515#section-4.1.8 + x509URL *string // https://tools.ietf.org/html/rfc7515#section-4.1.5 + privateParams map[string]any + mu *sync.RWMutex + dc DecodeCtx + raw []byte // stores the raw version of the header so it can be used later +} + +func NewHeaders() Headers { + return &stdHeaders{ + mu: &sync.RWMutex{}, + } +} + +func (h *stdHeaders) Algorithm() (jwa.SignatureAlgorithm, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.algorithm == nil { + return jwa.EmptySignatureAlgorithm(), false + } + return *(h.algorithm), true +} + +func (h *stdHeaders) ContentType() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.contentType == nil { + return "", false + } + return *(h.contentType), true +} + +func (h *stdHeaders) Critical() ([]string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.critical, true +} + +func (h *stdHeaders) JWK() (jwk.Key, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.jwk, true +} + +func (h *stdHeaders) JWKSetURL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.jwkSetURL == nil { + return "", false + } + return *(h.jwkSetURL), true +} + +func (h *stdHeaders) KeyID() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.keyID == nil { + return "", false + } + return *(h.keyID), true +} + +func (h *stdHeaders) Type() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.typ == nil { + return "", false + } + return *(h.typ), true +} + +func (h *stdHeaders) X509CertChain() (*cert.Chain, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + return h.x509CertChain, true +} + +func (h *stdHeaders) X509CertThumbprint() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprint == nil { + return "", false + } + return *(h.x509CertThumbprint), true +} + +func (h *stdHeaders) X509CertThumbprintS256() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509CertThumbprintS256 == nil { + return "", false + } + return *(h.x509CertThumbprintS256), true +} + +func (h *stdHeaders) X509URL() (string, bool) { + h.mu.RLock() + defer h.mu.RUnlock() + if h.x509URL == nil { + return "", false + } + return *(h.x509URL), true +} + +func (h *stdHeaders) clear() { + h.algorithm = nil + h.contentType = nil + h.critical = nil + h.jwk = nil + h.jwkSetURL = nil + h.keyID = nil + h.typ = nil + h.x509CertChain = nil + h.x509CertThumbprint = nil + h.x509CertThumbprintS256 = nil + h.x509URL = nil + h.privateParams = nil + h.raw = nil +} + +func (h *stdHeaders) DecodeCtx() DecodeCtx { + h.mu.RLock() + defer h.mu.RUnlock() + return h.dc +} + +func (h *stdHeaders) SetDecodeCtx(dc DecodeCtx) { + h.mu.Lock() + defer h.mu.Unlock() + h.dc = dc +} + +func (h *stdHeaders) rawBuffer() []byte { + return h.raw +} + +func (h *stdHeaders) PrivateParams() map[string]any { + h.mu.RLock() + defer h.mu.RUnlock() + return h.privateParams +} + +func (h *stdHeaders) Has(name string) bool { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AlgorithmKey: + return h.algorithm != nil + case ContentTypeKey: + return h.contentType != nil + case CriticalKey: + return h.critical != nil + case JWKKey: + return h.jwk != nil + case JWKSetURLKey: + return h.jwkSetURL != nil + case KeyIDKey: + return h.keyID != nil + case TypeKey: + return h.typ != nil + case X509CertChainKey: + return h.x509CertChain != nil + case X509CertThumbprintKey: + return h.x509CertThumbprint != nil + case X509CertThumbprintS256Key: + return h.x509CertThumbprintS256 != nil + case X509URLKey: + return h.x509URL != nil + default: + _, ok := h.privateParams[name] + return ok + } +} + +func (h *stdHeaders) Get(name string, dst any) error { + h.mu.RLock() + defer h.mu.RUnlock() + switch name { + case AlgorithmKey: + if h.algorithm == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.algorithm)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case ContentTypeKey: + if h.contentType == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.contentType)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case CriticalKey: + if h.critical == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, + h.critical); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case JWKKey: + if h.jwk == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, + h.jwk); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case JWKSetURLKey: + if h.jwkSetURL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.jwkSetURL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case KeyIDKey: + if h.keyID == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.keyID)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case TypeKey: + if h.typ == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.typ)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertChainKey: + if h.x509CertChain == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, + h.x509CertChain); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintKey: + if h.x509CertThumbprint == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprint)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509CertThumbprintS256Key: + if h.x509CertThumbprintS256 == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509CertThumbprintS256)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + case X509URLKey: + if h.x509URL == nil { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, *(h.x509URL)); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + return nil + default: + v, ok := h.privateParams[name] + if !ok { + return fmt.Errorf(`field %q not found`, name) + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return fmt.Errorf(`failed to assign value for field %q: %w`, name, err) + } + } + return nil +} + +func (h *stdHeaders) Set(name string, value any) error { + h.mu.Lock() + defer h.mu.Unlock() + return h.setNoLock(name, value) +} + +func (h *stdHeaders) setNoLock(name string, value any) error { + switch name { + case AlgorithmKey: + alg, err := jwa.KeyAlgorithmFrom(value) + if err != nil { + return fmt.Errorf("invalid value for %s key: %w", AlgorithmKey, err) + } + if salg, ok := alg.(jwa.SignatureAlgorithm); ok { + h.algorithm = &salg + return nil + } + return fmt.Errorf("expecte jwa.SignatureAlgorithm, received %T", alg) + case ContentTypeKey: + if v, ok := value.(string); ok { + h.contentType = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, ContentTypeKey, value) + case CriticalKey: + if v, ok := value.([]string); ok { + h.critical = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, CriticalKey, value) + case JWKKey: + if v, ok := value.(jwk.Key); ok { + h.jwk = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKKey, value) + case JWKSetURLKey: + if v, ok := value.(string); ok { + h.jwkSetURL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JWKSetURLKey, value) + case KeyIDKey: + if v, ok := value.(string); ok { + h.keyID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, KeyIDKey, value) + case TypeKey: + if v, ok := value.(string); ok { + h.typ = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, TypeKey, value) + case X509CertChainKey: + if v, ok := value.(*cert.Chain); ok { + h.x509CertChain = v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertChainKey, value) + case X509CertThumbprintKey: + if v, ok := value.(string); ok { + h.x509CertThumbprint = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintKey, value) + case X509CertThumbprintS256Key: + if v, ok := value.(string); ok { + h.x509CertThumbprintS256 = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509CertThumbprintS256Key, value) + case X509URLKey: + if v, ok := value.(string); ok { + h.x509URL = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, X509URLKey, value) + default: + if h.privateParams == nil { + h.privateParams = map[string]any{} + } + h.privateParams[name] = value + } + return nil +} + +func (h *stdHeaders) Remove(key string) error { + h.mu.Lock() + defer h.mu.Unlock() + switch key { + case AlgorithmKey: + h.algorithm = nil + case ContentTypeKey: + h.contentType = nil + case CriticalKey: + h.critical = nil + case JWKKey: + h.jwk = nil + case JWKSetURLKey: + h.jwkSetURL = nil + case KeyIDKey: + h.keyID = nil + case TypeKey: + h.typ = nil + case X509CertChainKey: + h.x509CertChain = nil + case X509CertThumbprintKey: + h.x509CertThumbprint = nil + case X509CertThumbprintS256Key: + h.x509CertThumbprintS256 = nil + case X509URLKey: + h.x509URL = nil + default: + delete(h.privateParams, key) + } + return nil +} + +func (h *stdHeaders) UnmarshalJSON(buf []byte) error { + h.mu.Lock() + defer h.mu.Unlock() + h.clear() + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case AlgorithmKey: + var decoded jwa.SignatureAlgorithm + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AlgorithmKey, err) + } + h.algorithm = &decoded + case ContentTypeKey: + if err := json.AssignNextStringToken(&h.contentType, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ContentTypeKey, err) + } + case CriticalKey: + var decoded []string + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, CriticalKey, err) + } + h.critical = decoded + case JWKKey: + var buf json.RawMessage + if err := dec.Decode(&buf); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JWKKey, err) + } + key, err := jwk.ParseKey(buf) + if err != nil { + return fmt.Errorf(`failed to parse JWK for key %s: %w`, JWKKey, err) + } + h.jwk = key + case JWKSetURLKey: + if err := json.AssignNextStringToken(&h.jwkSetURL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JWKSetURLKey, err) + } + case KeyIDKey: + if err := json.AssignNextStringToken(&h.keyID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, KeyIDKey, err) + } + case TypeKey: + if err := json.AssignNextStringToken(&h.typ, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, TypeKey, err) + } + case X509CertChainKey: + var decoded cert.Chain + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertChainKey, err) + } + h.x509CertChain = &decoded + case X509CertThumbprintKey: + if err := json.AssignNextStringToken(&h.x509CertThumbprint, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintKey, err) + } + case X509CertThumbprintS256Key: + if err := json.AssignNextStringToken(&h.x509CertThumbprintS256, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509CertThumbprintS256Key, err) + } + case X509URLKey: + if err := json.AssignNextStringToken(&h.x509URL, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, X509URLKey, err) + } + default: + decoded, err := registry.Decode(dec, tok) + if err != nil { + return err + } + h.setNoLock(tok, decoded) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + h.raw = buf + return nil +} + +func (h *stdHeaders) Keys() []string { + h.mu.RLock() + defer h.mu.RUnlock() + keys := make([]string, 0, 11+len(h.privateParams)) + if h.algorithm != nil { + keys = append(keys, AlgorithmKey) + } + if h.contentType != nil { + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + keys = append(keys, CriticalKey) + } + if h.jwk != nil { + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + keys = append(keys, X509URLKey) + } + for k := range h.privateParams { + keys = append(keys, k) + } + return keys +} + +func (h stdHeaders) MarshalJSON() ([]byte, error) { + h.mu.RLock() + data := make(map[string]any) + keys := make([]string, 0, 11+len(h.privateParams)) + if h.algorithm != nil { + data[AlgorithmKey] = *(h.algorithm) + keys = append(keys, AlgorithmKey) + } + if h.contentType != nil { + data[ContentTypeKey] = *(h.contentType) + keys = append(keys, ContentTypeKey) + } + if h.critical != nil { + data[CriticalKey] = h.critical + keys = append(keys, CriticalKey) + } + if h.jwk != nil { + data[JWKKey] = h.jwk + keys = append(keys, JWKKey) + } + if h.jwkSetURL != nil { + data[JWKSetURLKey] = *(h.jwkSetURL) + keys = append(keys, JWKSetURLKey) + } + if h.keyID != nil { + data[KeyIDKey] = *(h.keyID) + keys = append(keys, KeyIDKey) + } + if h.typ != nil { + data[TypeKey] = *(h.typ) + keys = append(keys, TypeKey) + } + if h.x509CertChain != nil { + data[X509CertChainKey] = h.x509CertChain + keys = append(keys, X509CertChainKey) + } + if h.x509CertThumbprint != nil { + data[X509CertThumbprintKey] = *(h.x509CertThumbprint) + keys = append(keys, X509CertThumbprintKey) + } + if h.x509CertThumbprintS256 != nil { + data[X509CertThumbprintS256Key] = *(h.x509CertThumbprintS256) + keys = append(keys, X509CertThumbprintS256Key) + } + if h.x509URL != nil { + data[X509URLKey] = *(h.x509URL) + keys = append(keys, X509URLKey) + } + for k, v := range h.privateParams { + data[k] = v + keys = append(keys, k) + } + h.mu.RUnlock() + sort.Strings(keys) + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + enc := json.NewEncoder(buf) + buf.WriteByte(tokens.OpenCurlyBracket) + for i, k := range keys { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(k) + buf.WriteString(`":`) + switch v := data[k].(type) { + case []byte: + buf.WriteRune(tokens.DoubleQuote) + buf.WriteString(base64.EncodeToString(v)) + buf.WriteRune(tokens.DoubleQuote) + default: + if err := enc.Encode(v); err != nil { + return nil, fmt.Errorf(`failed to encode value for field %s: %w`, k, err) + } + buf.Truncate(buf.Len() - 1) + } + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/interface.go new file mode 100644 index 0000000000..e3ad296844 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/interface.go @@ -0,0 +1,80 @@ +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/jws/legacy" +) + +type Signer = legacy.Signer +type Verifier = legacy.Verifier +type HMACSigner = legacy.HMACSigner +type HMACVerifier = legacy.HMACVerifier + +// Base64Encoder is an interface that can be used when encoding JWS message +// components to base64. This is useful when you want to use a non-standard +// base64 encoder while generating or verifying signatures. By default JWS +// uses raw url base64 encoding (without padding), but there are apparently +// some cases where you may want to use a base64 encoders that uses padding. +// +// For example, apparently AWS ALB User Claims is provided in JWT format, +// but it uses a base64 encoding with padding. +type Base64Encoder = base64.Encoder + +type DecodeCtx interface { + CollectRaw() bool +} + +// Message represents a full JWS encoded message. Flattened serialization +// is not supported as a struct, but rather it's represented as a +// Message struct with only one `signature` element. +// +// Do not expect to use the Message object to verify or construct a +// signed payload with. You should only use this when you want to actually +// programmatically view the contents of the full JWS payload. +// +// As of this version, there is one big incompatibility when using Message +// objects to convert between compact and JSON representations. +// The protected header is sometimes encoded differently from the original +// message and the JSON serialization that we use in Go. +// +// For example, the protected header `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9` +// decodes to +// +// {"typ":"JWT", +// "alg":"HS256"} +// +// However, when we parse this into a message, we create a jws.Header object, +// which, when we marshal into a JSON object again, becomes +// +// {"typ":"JWT","alg":"HS256"} +// +// Notice that serialization lacks a line break and a space between `"JWT",` +// and `"alg"`. This causes a problem when verifying the signatures AFTER +// a compact JWS message has been unmarshaled into a jws.Message. +// +// jws.Verify() doesn't go through this step, and therefore this does not +// manifest itself. However, you may see this discrepancy when you manually +// go through these conversions, and/or use the `jwx` tool like so: +// +// jwx jws parse message.jws | jwx jws verify --key somekey.jwk --stdin +// +// In this scenario, the first `jwx jws parse` outputs a parsed jws.Message +// which is marshaled into JSON. At this point the message's protected +// headers and the signatures don't match. +// +// To sign and verify, use the appropriate `Sign()` and `Verify()` functions. +type Message struct { + dc DecodeCtx + payload []byte + signatures []*Signature + b64 bool // true if payload should be base64 encoded +} + +type Signature struct { + encoder Base64Encoder + dc DecodeCtx + headers Headers // Unprotected Headers + protected Headers // Protected Headers + signature []byte // Signature + detached bool +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/BUILD.bazel new file mode 100644 index 0000000000..eb8bd94acb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/BUILD.bazel @@ -0,0 +1,11 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "keytype", + srcs = ["keytype.go"], + importpath = "github.com/lestrrat-go/jwx/v3/jws/internal/keytype", + visibility = ["//jws:__subpackages__"], + deps = [ + "//jwk", + ], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/keytype.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/keytype.go new file mode 100644 index 0000000000..6b57ed10d8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/internal/keytype/keytype.go @@ -0,0 +1,57 @@ +package keytype + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// Because the keys defined in github.com/lestrrat-go/jwx/jwk may also implement +// crypto.Signer, it would be possible for to mix up key types when signing/verifying +// for example, when we specify jws.WithKey(jwa.RSA256, cryptoSigner), the cryptoSigner +// can be for RSA, or any other type that implements crypto.Signer... even if it's for the +// wrong algorithm. +// +// These functions are there to differentiate between the valid KNOWN key types. +// For any other key type that is outside of the Go std library and our own code, +// we must rely on the user to be vigilant. +// +// Notes: symmetric keys are obviously not part of this. for v2 OKP keys, +// x25519 does not implement Sign() +func IsValidRSAKey(key any) bool { + switch key.(type) { + case + ecdsa.PrivateKey, *ecdsa.PrivateKey, + ed25519.PrivateKey, + jwk.ECDSAPrivateKey, jwk.OKPPrivateKey: + // these are NOT ok + return false + } + return true +} + +func IsValidECDSAKey(key any) bool { + switch key.(type) { + case + ed25519.PrivateKey, + rsa.PrivateKey, *rsa.PrivateKey, + jwk.RSAPrivateKey, jwk.OKPPrivateKey: + // these are NOT ok + return false + } + return true +} + +func IsValidEDDSAKey(key any) bool { + switch key.(type) { + case + ecdsa.PrivateKey, *ecdsa.PrivateKey, + rsa.PrivateKey, *rsa.PrivateKey, + jwk.RSAPrivateKey, jwk.ECDSAPrivateKey: + // these are NOT ok + return false + } + return true +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/io.go new file mode 100644 index 0000000000..77a084cfda --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/io.go @@ -0,0 +1,36 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jws + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (*Message, error) { + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jws.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jws.go new file mode 100644 index 0000000000..b41b2758b8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jws.go @@ -0,0 +1,658 @@ +//go:generate ../tools/cmd/genjws.sh + +// Package jws implements the digital signature on JSON based data +// structures as described in https://tools.ietf.org/html/rfc7515 +// +// If you do not care about the details, the only things that you +// would need to use are the following functions: +// +// jws.Sign(payload, jws.WithKey(algorithm, key)) +// jws.Verify(serialized, jws.WithKey(algorithm, key)) +// +// To sign, simply use `jws.Sign`. `payload` is a []byte buffer that +// contains whatever data you want to sign. `alg` is one of the +// jwa.SignatureAlgorithm constants from package jwa. For RSA and +// ECDSA family of algorithms, you will need to prepare a private key. +// For HMAC family, you just need a []byte value. The `jws.Sign` +// function will return the encoded JWS message on success. +// +// To verify, use `jws.Verify`. It will parse the `encodedjws` buffer +// and verify the result using `algorithm` and `key`. Upon successful +// verification, the original payload is returned, so you can work on it. +package jws + +import ( + "bufio" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "errors" + "fmt" + "io" + "reflect" + "sync" + "unicode" + "unicode/utf8" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/jwxio" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +var registry = json.NewRegistry() + +var signers = make(map[jwa.SignatureAlgorithm]Signer) +var muSigner = &sync.Mutex{} + +func removeSigner(alg jwa.SignatureAlgorithm) { + muSigner.Lock() + defer muSigner.Unlock() + delete(signers, alg) +} + +type defaultSigner struct { + alg jwa.SignatureAlgorithm +} + +func (s defaultSigner) Algorithm() jwa.SignatureAlgorithm { + return s.alg +} + +func (s defaultSigner) Sign(key any, payload []byte) ([]byte, error) { + return jwsbb.Sign(key, s.alg.String(), payload, nil) +} + +type signerAdapter struct { + signer Signer +} + +func (s signerAdapter) Algorithm() jwa.SignatureAlgorithm { + return s.signer.Algorithm() +} + +func (s signerAdapter) Sign(key any, payload []byte) ([]byte, error) { + return s.signer.Sign(payload, key) +} + +const ( + fmtInvalid = 1 << iota + fmtCompact + fmtJSON + fmtJSONPretty + fmtMax +) + +// silence linters +var _ = fmtInvalid +var _ = fmtMax + +func validateKeyBeforeUse(key any) error { + jwkKey, ok := key.(jwk.Key) + if !ok { + converted, err := jwk.Import(key) + if err != nil { + return fmt.Errorf(`could not convert key of type %T to jwk.Key for validation: %w`, key, err) + } + jwkKey = converted + } + return jwkKey.Validate() +} + +// Sign generates a JWS message for the given payload and returns +// it in serialized form, which can be in either compact or +// JSON format. Default is compact. +// +// You must pass at least one key to `jws.Sign()` by using `jws.WithKey()` +// option. +// +// jws.Sign(payload, jws.WithKey(alg, key)) +// jws.Sign(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) +// +// Note that in the second example the `jws.WithJSON()` option is +// specified as well. This is because the compact serialization +// format does not support multiple signatures, and users must +// specifically ask for the JSON serialization format. +// +// Read the documentation for `jws.WithKey()` to learn more about the +// possible values that can be used for `alg` and `key`. +// +// You may create JWS messages with the "none" (jwa.NoSignature) algorithm +// if you use the `jws.WithInsecureNoSignature()` option. This option +// can be combined with one or more signature keys, as well as the +// `jws.WithJSON()` option to generate multiple signatures (though +// the usefulness of such constructs is highly debatable) +// +// Note that this library does not allow you to successfully call `jws.Verify()` on +// signatures with the "none" algorithm. To parse these, use `jws.Parse()` instead. +// +// If you want to use a detached payload, use `jws.WithDetachedPayload()` as +// one of the options. When you use this option, you must always set the +// first parameter (`payload`) to `nil`, or the function will return an error +// +// You may also want to look at how to pass protected headers to the +// signing process, as you will likely be required to set the `b64` field +// when using detached payload. +// +// Look for options that return `jws.SignOption` or `jws.SignVerifyOption` +// for a complete list of options that can be passed to this function. +// +// You can use `errors.Is` with `jws.SignError()` to check if an error is from this function. +func Sign(payload []byte, options ...SignOption) ([]byte, error) { + sc := signContextPool.Get() + defer signContextPool.Put(sc) + + sc.payload = payload + + if err := sc.ProcessOptions(options); err != nil { + return nil, signerr(`failed to process options: %w`, err) + } + + lsigner := len(sc.sigbuilders) + if lsigner == 0 { + return nil, signerr(`no signers available. Specify an algorithm and a key using jws.WithKey()`) + } + + // Design note: while we could have easily set format = fmtJSON when + // lsigner > 1, I believe the decision to change serialization formats + // must be explicitly stated by the caller. Otherwise, I'm pretty sure + // there would be people filing issues saying "I get JSON when I expected + // compact serialization". + // + // Therefore, instead of making implicit format conversions, we force the + // user to spell it out as `jws.Sign(..., jws.WithJSON(), jws.WithKey(...), jws.WithKey(...))` + if sc.format == fmtCompact && lsigner != 1 { + return nil, signerr(`cannot have multiple signers (keys) specified for compact serialization. Use only one jws.WithKey()`) + } + + // Create a Message object with all the bits and bobs, and we'll + // serialize it in the end + var result Message + + if err := sc.PopulateMessage(&result); err != nil { + return nil, signerr(`failed to populate message: %w`, err) + } + switch sc.format { + case fmtJSON: + return json.Marshal(result) + case fmtJSONPretty: + return json.MarshalIndent(result, "", " ") + case fmtCompact: + // Take the only signature object, and convert it into a Compact + // serialization format + var compactOpts []CompactOption + if sc.detached { + compactOpts = append(compactOpts, WithDetached(true)) + } + for _, option := range options { + if copt, ok := option.(CompactOption); ok { + compactOpts = append(compactOpts, copt) + } + } + return Compact(&result, compactOpts...) + default: + return nil, signerr(`invalid serialization format`) + } +} + +var allowNoneWhitelist = jwk.WhitelistFunc(func(string) bool { + return false +}) + +// Verify checks if the given JWS message is verifiable using `alg` and `key`. +// `key` may be a "raw" key (e.g. rsa.PublicKey) or a jwk.Key +// +// If the verification is successful, `err` is nil, and the content of the +// payload that was signed is returned. If you need more fine-grained +// control of the verification process, manually generate a +// `Verifier` in `verify` subpackage, and call `Verify` method on it. +// If you need to access signatures and JOSE headers in a JWS message, +// use `Parse` function to get `Message` object. +// +// Because the use of "none" (jwa.NoSignature) algorithm is strongly discouraged, +// this function DOES NOT consider it a success when `{"alg":"none"}` is +// encountered in the message (it would also be counterintuitive when the code says +// it _verified_ something when in fact it did no such thing). If you want to +// accept messages with "none" signature algorithm, use `jws.Parse` to get the +// raw JWS message. +// +// The error returned by this function is of type can be checked against +// `jws.VerifyError()` and `jws.VerificationError()`. The latter is returned +// when the verification process itself fails (e.g. invalid signature, wrong key), +// while the former is returned when any other part of the `jws.Verify()` +// function fails. +func Verify(buf []byte, options ...VerifyOption) ([]byte, error) { + vc := verifyContextPool.Get() + defer verifyContextPool.Put(vc) + + if err := vc.ProcessOptions(options); err != nil { + return nil, verifyerr(`failed to process options: %w`, err) + } + + return vc.VerifyMessage(buf) +} + +// get the value of b64 header field. +// If the field does not exist, returns true (default) +// Otherwise return the value specified by the header field. +func getB64Value(hdr Headers) bool { + var b64 bool + if err := hdr.Get("b64", &b64); err != nil { + return true // default + } + + return b64 +} + +// Parse parses contents from the given source and creates a jws.Message +// struct. By default the input can be in either compact or full JSON serialization. +// +// You may pass `jws.WithJSON()` and/or `jws.WithCompact()` to specify +// explicitly which format to use. If neither or both is specified, the function +// will attempt to autodetect the format. If one or the other is specified, +// only the specified format will be attempted. +// +// On error, returns a jws.ParseError. +func Parse(src []byte, options ...ParseOption) (*Message, error) { + var formats int + for _, option := range options { + switch option.Ident() { + case identSerialization{}: + var v int + if err := option.Value(&v); err != nil { + return nil, parseerr(`failed to retrieve serialization option value: %w`, err) + } + switch v { + case fmtJSON: + formats |= fmtJSON + case fmtCompact: + formats |= fmtCompact + } + } + } + + // if format is 0 or both JSON/Compact, auto detect + if v := formats & (fmtJSON | fmtCompact); v == 0 || v == fmtJSON|fmtCompact { + CHECKLOOP: + for i := range src { + r := rune(src[i]) + if r >= utf8.RuneSelf { + r, _ = utf8.DecodeRune(src) + } + if !unicode.IsSpace(r) { + if r == tokens.OpenCurlyBracket { + formats = fmtJSON + } else { + formats = fmtCompact + } + break CHECKLOOP + } + } + } + + if formats&fmtCompact == fmtCompact { + msg, err := parseCompact(src) + if err != nil { + return nil, parseerr(`failed to parse compact format: %w`, err) + } + return msg, nil + } else if formats&fmtJSON == fmtJSON { + msg, err := parseJSON(src) + if err != nil { + return nil, parseerr(`failed to parse JSON format: %w`, err) + } + return msg, nil + } + + return nil, parseerr(`invalid byte sequence`) +} + +// ParseString parses contents from the given source and creates a jws.Message +// struct. The input can be in either compact or full JSON serialization. +// +// On error, returns a jws.ParseError. +func ParseString(src string) (*Message, error) { + msg, err := Parse([]byte(src)) + if err != nil { + return nil, sparseerr(`failed to parse string: %w`, err) + } + return msg, nil +} + +// ParseReader parses contents from the given source and creates a jws.Message +// struct. The input can be in either compact or full JSON serialization. +// +// On error, returns a jws.ParseError. +func ParseReader(src io.Reader) (*Message, error) { + data, err := jwxio.ReadAllFromFiniteSource(src) + if err == nil { + return Parse(data) + } + + if !errors.Is(err, jwxio.NonFiniteSourceError()) { + return nil, rparseerr(`failed to read from finite source: %w`, err) + } + + rdr := bufio.NewReader(src) + var first rune + for { + r, _, err := rdr.ReadRune() + if err != nil { + return nil, rparseerr(`failed to read rune: %w`, err) + } + if !unicode.IsSpace(r) { + first = r + if err := rdr.UnreadRune(); err != nil { + return nil, rparseerr(`failed to unread rune: %w`, err) + } + + break + } + } + + var parser func(io.Reader) (*Message, error) + if first == tokens.OpenCurlyBracket { + parser = parseJSONReader + } else { + parser = parseCompactReader + } + + m, err := parser(rdr) + if err != nil { + return nil, rparseerr(`failed to parse reader: %w`, err) + } + + return m, nil +} + +func parseJSONReader(src io.Reader) (result *Message, err error) { + var m Message + if err := json.NewDecoder(src).Decode(&m); err != nil { + return nil, fmt.Errorf(`failed to unmarshal jws message: %w`, err) + } + return &m, nil +} + +func parseJSON(data []byte) (result *Message, err error) { + var m Message + if err := json.Unmarshal(data, &m); err != nil { + return nil, fmt.Errorf(`failed to unmarshal jws message: %w`, err) + } + return &m, nil +} + +// SplitCompact splits a JWS in compact format and returns its three parts +// separately: protected headers, payload and signature. +// On error, returns a jws.ParseError. +// +// This function will be deprecated in v4. It is a low-level API, and +// thus will be available in the `jwsbb` package. +func SplitCompact(src []byte) ([]byte, []byte, []byte, error) { + hdr, payload, signature, err := jwsbb.SplitCompact(src) + if err != nil { + return nil, nil, nil, parseerr(`%w`, err) + } + return hdr, payload, signature, nil +} + +// SplitCompactString splits a JWT and returns its three parts +// separately: protected headers, payload and signature. +// On error, returns a jws.ParseError. +// +// This function will be deprecated in v4. It is a low-level API, and +// thus will be available in the `jwsbb` package. +func SplitCompactString(src string) ([]byte, []byte, []byte, error) { + hdr, payload, signature, err := jwsbb.SplitCompactString(src) + if err != nil { + return nil, nil, nil, parseerr(`%w`, err) + } + return hdr, payload, signature, nil +} + +// SplitCompactReader splits a JWT and returns its three parts +// separately: protected headers, payload and signature. +// On error, returns a jws.ParseError. +// +// This function will be deprecated in v4. It is a low-level API, and +// thus will be available in the `jwsbb` package. +func SplitCompactReader(rdr io.Reader) ([]byte, []byte, []byte, error) { + hdr, payload, signature, err := jwsbb.SplitCompactReader(rdr) + if err != nil { + return nil, nil, nil, parseerr(`%w`, err) + } + return hdr, payload, signature, nil +} + +// parseCompactReader parses a JWS value serialized via compact serialization. +func parseCompactReader(rdr io.Reader) (m *Message, err error) { + protected, payload, signature, err := SplitCompactReader(rdr) + if err != nil { + return nil, fmt.Errorf(`invalid compact serialization format: %w`, err) + } + return parse(protected, payload, signature) +} + +func parseCompact(data []byte) (m *Message, err error) { + protected, payload, signature, err := SplitCompact(data) + if err != nil { + return nil, fmt.Errorf(`invalid compact serialization format: %w`, err) + } + return parse(protected, payload, signature) +} + +func parse(protected, payload, signature []byte) (*Message, error) { + decodedHeader, err := base64.Decode(protected) + if err != nil { + return nil, fmt.Errorf(`failed to decode protected headers: %w`, err) + } + + hdr := NewHeaders() + if err := json.Unmarshal(decodedHeader, hdr); err != nil { + return nil, fmt.Errorf(`failed to parse JOSE headers: %w`, err) + } + + var decodedPayload []byte + b64 := getB64Value(hdr) + if !b64 { + decodedPayload = payload + } else { + v, err := base64.Decode(payload) + if err != nil { + return nil, fmt.Errorf(`failed to decode payload: %w`, err) + } + decodedPayload = v + } + + decodedSignature, err := base64.Decode(signature) + if err != nil { + return nil, fmt.Errorf(`failed to decode signature: %w`, err) + } + + var msg Message + msg.payload = decodedPayload + msg.signatures = append(msg.signatures, &Signature{ + protected: hdr, + signature: decodedSignature, + }) + msg.b64 = b64 + return &msg, nil +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jws.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = hdr.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC1123 format string: +// +// jws.RegisterCustomField(`x-birthday`, jws.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC1123, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} + +// Helpers for signature verification +var rawKeyToKeyType = make(map[reflect.Type]jwa.KeyType) +var keyTypeToAlgorithms = make(map[jwa.KeyType][]jwa.SignatureAlgorithm) + +func init() { + rawKeyToKeyType[reflect.TypeOf([]byte(nil))] = jwa.OctetSeq() + rawKeyToKeyType[reflect.TypeOf(ed25519.PublicKey(nil))] = jwa.OKP() + rawKeyToKeyType[reflect.TypeOf(rsa.PublicKey{})] = jwa.RSA() + rawKeyToKeyType[reflect.TypeOf((*rsa.PublicKey)(nil))] = jwa.RSA() + rawKeyToKeyType[reflect.TypeOf(ecdsa.PublicKey{})] = jwa.EC() + rawKeyToKeyType[reflect.TypeOf((*ecdsa.PublicKey)(nil))] = jwa.EC() + + addAlgorithmForKeyType(jwa.OKP(), jwa.EdDSA()) + for _, alg := range []jwa.SignatureAlgorithm{jwa.HS256(), jwa.HS384(), jwa.HS512()} { + addAlgorithmForKeyType(jwa.OctetSeq(), alg) + } + for _, alg := range []jwa.SignatureAlgorithm{jwa.RS256(), jwa.RS384(), jwa.RS512(), jwa.PS256(), jwa.PS384(), jwa.PS512()} { + addAlgorithmForKeyType(jwa.RSA(), alg) + } + for _, alg := range []jwa.SignatureAlgorithm{jwa.ES256(), jwa.ES384(), jwa.ES512()} { + addAlgorithmForKeyType(jwa.EC(), alg) + } +} + +func addAlgorithmForKeyType(kty jwa.KeyType, alg jwa.SignatureAlgorithm) { + keyTypeToAlgorithms[kty] = append(keyTypeToAlgorithms[kty], alg) +} + +// AlgorithmsForKey returns the possible signature algorithms that can +// be used for a given key. It only takes in consideration keys/algorithms +// for verification purposes, as this is the only usage where one may need +// dynamically figure out which method to use. +func AlgorithmsForKey(key any) ([]jwa.SignatureAlgorithm, error) { + var kty jwa.KeyType + switch key := key.(type) { + case jwk.Key: + kty = key.KeyType() + case rsa.PublicKey, *rsa.PublicKey, rsa.PrivateKey, *rsa.PrivateKey: + kty = jwa.RSA() + case ecdsa.PublicKey, *ecdsa.PublicKey, ecdsa.PrivateKey, *ecdsa.PrivateKey: + kty = jwa.EC() + case ed25519.PublicKey, ed25519.PrivateKey, *ecdh.PublicKey, ecdh.PublicKey, *ecdh.PrivateKey, ecdh.PrivateKey: + kty = jwa.OKP() + case []byte: + kty = jwa.OctetSeq() + default: + return nil, fmt.Errorf(`unknown key type %T`, key) + } + + algs, ok := keyTypeToAlgorithms[kty] + if !ok { + return nil, fmt.Errorf(`unregistered key type %q`, kty) + } + return algs, nil +} + +func Settings(options ...GlobalOption) { + for _, option := range options { + switch option.Ident() { + case identLegacySigners{}: + enableLegacySigners() + } + } +} + +// VerifyCompactFast is a fast path verification function for JWS messages +// in compact serialization format. +// +// This function is considered experimental, and may change or be removed +// in the future. +// +// VerifyCompactFast performs signature verification on a JWS compact +// serialization without fully parsing the message into a jws.Message object. +// This makes it more efficient for cases where you only need to verify +// the signature and extract the payload, without needing access to headers +// or other JWS metadata. +// +// Returns the original payload that was signed if verification succeeds. +// +// Unlike jws.Verify(), this function requires you to specify the +// algorithm explicitly rather than extracting it from the JWS headers. +// This can be useful for performance-critical applications where the +// algorithm is known in advance. +// +// Since this function avoids doing many checks that jws.Verify would perform, +// you must ensure to perform the necessary checks including ensuring that algorithm is safe to use for your payload yourself. +func VerifyCompactFast(key any, compact []byte, alg jwa.SignatureAlgorithm) ([]byte, error) { + algstr := alg.String() + + // Split the serialized JWT into its components + hdr, payload, encodedSig, err := jwsbb.SplitCompact(compact) + if err != nil { + return nil, fmt.Errorf("jwt.verifyFast: failed to split compact: %w", err) + } + + signature, err := base64.Decode(encodedSig) + if err != nil { + return nil, fmt.Errorf("jwt.verifyFast: failed to decode signature: %w", err) + } + + // Instead of appending, copy the data from hdr/payload + lvb := len(hdr) + 1 + len(payload) + verifyBuf := pool.ByteSlice().GetCapacity(lvb) + verifyBuf = verifyBuf[:lvb] + copy(verifyBuf, hdr) + verifyBuf[len(hdr)] = tokens.Period + copy(verifyBuf[len(hdr)+1:], payload) + defer pool.ByteSlice().Put(verifyBuf) + + // Verify the signature + if verifier2, err := VerifierFor(alg); err == nil { + if err := verifier2.Verify(key, verifyBuf, signature); err != nil { + return nil, verifyError{verificationError{fmt.Errorf("jwt.VerifyCompact: signature verification failed for %s: %w", algstr, err)}} + } + } else { + legacyVerifier, err := NewVerifier(alg) + if err != nil { + return nil, verifyerr("jwt.VerifyCompact: failed to create verifier for %s: %w", algstr, err) + } + if err := legacyVerifier.Verify(verifyBuf, signature, key); err != nil { + return nil, verifyError{verificationError{fmt.Errorf("jwt.VerifyCompact: signature verification failed for %s: %w", algstr, err)}} + } + } + + decoded, err := base64.Decode(payload) + if err != nil { + return nil, verifyerr("jwt.VerifyCompact: failed to decode payload: %w", err) + } + return decoded, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/BUILD.bazel new file mode 100644 index 0000000000..f8fcdac4ab --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/BUILD.bazel @@ -0,0 +1,37 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwsbb", + srcs = [ + "crypto_signer.go", + "ecdsa.go", + "eddsa.go", + "format.go", + "hmac.go", + "jwsbb.go", + "rsa.go", + "sign.go", + "verify.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jws/jwsbb", + visibility = ["//visibility:public"], + deps = [ + "//internal/base64", + "//internal/ecutil", + "//internal/jwxio", + "//internal/keyconv", + "//internal/pool", + "//internal/tokens", + "//jws/internal/keytype", + ], +) + +go_test( + name = "jwsbb_test", + srcs = ["jwsbb_test.go"], + embed = [":jwsbb"], + deps = [ + "//internal/base64", + "@com_github_stretchr_testify//require", + ], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/crypto_signer.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/crypto_signer.go new file mode 100644 index 0000000000..bd6132a4c5 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/crypto_signer.go @@ -0,0 +1,45 @@ +package jwsbb + +import ( + "crypto" + "crypto/rand" + "fmt" + "io" +) + +// cryptosign is a low-level function that signs a payload using a crypto.Signer. +// If hash is crypto.Hash(0), the payload is signed directly without hashing. +// Otherwise, the payload is hashed using the specified hash function before signing. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +func cryptosign(signer crypto.Signer, payload []byte, hash crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { + if rr == nil { + rr = rand.Reader + } + + var digest []byte + if hash == crypto.Hash(0) { + digest = payload + } else { + h := hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload to hash: %w`, err) + } + digest = h.Sum(nil) + } + return signer.Sign(rr, digest, opts) +} + +// SignCryptoSigner generates a signature using a crypto.Signer interface. +// This function can be used for hardware security modules, smart cards, +// and other implementations of the crypto.Signer interface. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +// +// Returns the signature bytes or an error if signing fails. +func SignCryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { + if signer == nil { + return nil, fmt.Errorf("jwsbb.SignCryptoSignerRaw: signer is nil") + } + return cryptosign(signer, raw, h, opts, rr) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/ecdsa.go new file mode 100644 index 0000000000..bd7ef4adc9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/ecdsa.go @@ -0,0 +1,216 @@ +package jwsbb + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "encoding/asn1" + "fmt" + "io" + "math/big" + + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +var ecdsaHashFuncs = map[string]crypto.Hash{ + "ES256": crypto.SHA256, + "ES256K": crypto.SHA256, + "ES384": crypto.SHA384, + "ES512": crypto.SHA512, +} + +func isSuppotedECDSAAlgorithm(alg string) bool { + _, ok := ecdsaHashFuncs[alg] + return ok +} + +func ECDSAHashFuncFor(alg string) (crypto.Hash, error) { + if h, ok := ecdsaHashFuncs[alg]; ok { + return h, nil + } + return 0, fmt.Errorf(`unsupported ECDSA algorithm %s`, alg) +} + +func ecdsaGetSignerKey(key any) (*ecdsa.PrivateKey, crypto.Signer, bool, error) { + cs, isCryptoSigner := key.(crypto.Signer) + if isCryptoSigner { + if !keytype.IsValidECDSAKey(key) { + return nil, nil, false, fmt.Errorf(`cannot use key of type %T`, key) + } + switch key.(type) { + case ecdsa.PrivateKey, *ecdsa.PrivateKey: + // if it's ecdsa.PrivateKey, it's more efficient to + // go through the non-crypto.Signer route. Set isCryptoSigner to false + isCryptoSigner = false + } + } + + if isCryptoSigner { + return nil, cs, true, nil + } + + var privkey *ecdsa.PrivateKey + if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil { + return nil, nil, false, fmt.Errorf(`invalid key type %T. ecdsa.PrivateKey is required: %w`, key, err) + } + return privkey, nil, false, nil +} + +// UnpackASN1ECDSASignature unpacks an ASN.1 encoded ECDSA signature into r and s values. +// This is typically used when working with crypto.Signer interfaces that return ASN.1 encoded signatures. +func UnpackASN1ECDSASignature(signed []byte, r, s *big.Int) error { + // Okay, this is silly, but hear me out. When we use the + // crypto.Signer interface, the PrivateKey is hidden. + // But we need some information about the key (its bit size). + // + // So while silly, we're going to have to make another call + // here and fetch the Public key. + // (This probably means that this information should be cached somewhere) + var p struct { + R *big.Int // TODO: get this from a pool? + S *big.Int + } + if _, err := asn1.Unmarshal(signed, &p); err != nil { + return fmt.Errorf(`failed to unmarshal ASN1 encoded signature: %w`, err) + } + + r.Set(p.R) + s.Set(p.S) + return nil +} + +// UnpackECDSASignature unpacks a JWS-format ECDSA signature into r and s values. +// The signature should be in the format specified by RFC 7515 (r||s as fixed-length byte arrays). +func UnpackECDSASignature(signature []byte, pubkey *ecdsa.PublicKey, r, s *big.Int) error { + keySize := ecutil.CalculateKeySize(pubkey.Curve) + if len(signature) != keySize*2 { + return fmt.Errorf(`invalid signature length for curve %q`, pubkey.Curve.Params().Name) + } + + r.SetBytes(signature[:keySize]) + s.SetBytes(signature[keySize:]) + + return nil +} + +// PackECDSASignature packs the r and s values from an ECDSA signature into a JWS-format byte slice. +// The output format follows RFC 7515: r||s as fixed-length byte arrays. +func PackECDSASignature(r *big.Int, sbig *big.Int, curveBits int) ([]byte, error) { + keyBytes := curveBits / 8 + if curveBits%8 > 0 { + keyBytes++ + } + + // Serialize r and s into fixed-length bytes + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := sbig.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + // Output as r||s + return append(rBytesPadded, sBytesPadded...), nil +} + +// SignECDSA generates an ECDSA signature for the given payload using the specified private key and hash. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// +// rr is an io.Reader that provides randomness for signing. if rr is nil, it defaults to rand.Reader. +func SignECDSA(key *ecdsa.PrivateKey, payload []byte, h crypto.Hash, rr io.Reader) ([]byte, error) { + hh := h.New() + if _, err := hh.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using ecdsa: %w`, err) + } + digest := hh.Sum(nil) + + if rr == nil { + rr = rand.Reader + } + + // Sign and get r, s values + r, s, err := ecdsa.Sign(rr, key, digest) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using ecdsa: %w`, err) + } + + return PackECDSASignature(r, s, key.Curve.Params().BitSize) +} + +// SignECDSACryptoSigner generates an ECDSA signature using a crypto.Signer interface. +// This function works with hardware security modules and other crypto.Signer implementations. +// The signature is converted from ASN.1 format to JWS format (r||s). +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +func SignECDSACryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, rr io.Reader) ([]byte, error) { + signed, err := SignCryptoSigner(signer, raw, h, h, rr) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using crypto.Signer: %w`, err) + } + + return signECDSACryptoSigner(signer, signed) +} + +func signECDSACryptoSigner(signer crypto.Signer, signed []byte) ([]byte, error) { + cpub := signer.Public() + pubkey, ok := cpub.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey) + } + curveBits := pubkey.Curve.Params().BitSize + + var r, s big.Int + if err := UnpackASN1ECDSASignature(signed, &r, &s); err != nil { + return nil, fmt.Errorf(`failed to unpack ASN1 encoded signature: %w`, err) + } + + return PackECDSASignature(&r, &s, curveBits) +} + +func ecdsaVerify(key *ecdsa.PublicKey, buf []byte, h crypto.Hash, r, s *big.Int) error { + hasher := h.New() + hasher.Write(buf) + digest := hasher.Sum(nil) + if !ecdsa.Verify(key, digest, r, s) { + return fmt.Errorf("jwsbb.ECDSAVerifier: invalid ECDSA signature") + } + return nil +} + +// VerifyECDSA verifies an ECDSA signature for the given payload. +// This function verifies the signature using the specified public key and hash algorithm. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyECDSA(key *ecdsa.PublicKey, payload, signature []byte, h crypto.Hash) error { + var r, s big.Int + if err := UnpackECDSASignature(signature, key, &r, &s); err != nil { + return fmt.Errorf("jwsbb.ECDSAVerifier: failed to unpack ECDSA signature: %w", err) + } + + return ecdsaVerify(key, payload, h, &r, &s) +} + +// VerifyECDSACryptoSigner verifies an ECDSA signature for crypto.Signer implementations. +// This function is useful for verifying signatures created by hardware security modules +// or other implementations of the crypto.Signer interface. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyECDSACryptoSigner(signer crypto.Signer, payload, signature []byte, h crypto.Hash) error { + var pubkey *ecdsa.PublicKey + switch cpub := signer.Public(); cpub := cpub.(type) { + case ecdsa.PublicKey: + pubkey = &cpub + case *ecdsa.PublicKey: + pubkey = cpub + default: + return fmt.Errorf(`jwsbb.VerifyECDSACryptoSigner: expected *ecdsa.PublicKey, got %T`, cpub) + } + + var r, s big.Int + if err := UnpackECDSASignature(signature, pubkey, &r, &s); err != nil { + return fmt.Errorf("jwsbb.ECDSAVerifier: failed to unpack ASN.1 encoded ECDSA signature: %w", err) + } + + return ecdsaVerify(pubkey, payload, h, &r, &s) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/eddsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/eddsa.go new file mode 100644 index 0000000000..a5e41d2ecc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/eddsa.go @@ -0,0 +1,52 @@ +package jwsbb + +import ( + "crypto" + "crypto/ed25519" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +func isSupportedEdDSAAlgorithm(alg string) bool { + return alg == "EdDSA" +} + +func eddsaGetSigner(key any) (crypto.Signer, error) { + // The ed25519.PrivateKey object implements crypto.Signer, so we should + // simply accept a crypto.Signer here. + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidEDDSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate EdDSA based signatures`, key) + } + return signer, nil + } + + // This fallback exists for cases when jwk.Key was passed, or + // users gave us a pointer instead of non-pointer, etc. + var privkey ed25519.PrivateKey + if err := keyconv.Ed25519PrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve ed25519.PrivateKey out of %T: %w`, key, err) + } + return privkey, nil +} + +// SignEdDSA generates an EdDSA (Ed25519) signature for the given payload. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// EdDSA is deterministic and doesn't require additional hashing of the input. +func SignEdDSA(key ed25519.PrivateKey, payload []byte) ([]byte, error) { + return ed25519.Sign(key, payload), nil +} + +// VerifyEdDSA verifies an EdDSA (Ed25519) signature for the given payload. +// This function verifies the signature using Ed25519 verification algorithm. +// The payload parameter should be the pre-computed signing input (typically header.payload). +// EdDSA is deterministic and provides strong security guarantees without requiring hash function selection. +func VerifyEdDSA(key ed25519.PublicKey, payload, signature []byte) error { + if !ed25519.Verify(key, payload, signature) { + return fmt.Errorf("invalid EdDSA signature") + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/format.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/format.go new file mode 100644 index 0000000000..430bf625ac --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/format.go @@ -0,0 +1,235 @@ +package jwsbb + +import ( + "bytes" + "errors" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/jwxio" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// SignBuffer combines the base64-encoded header and payload into a single byte slice +// for signing purposes. This creates the signing input according to JWS specification (RFC 7515). +// The result should be passed to signature generation functions. +// +// Parameters: +// - buf: Reusable buffer (can be nil for automatic allocation) +// - hdr: Raw header bytes (will be base64-encoded) +// - payload: Raw payload bytes (encoded based on encodePayload flag) +// - encoder: Base64 encoder to use for encoding components +// - encodePayload: If true, payload is base64-encoded; if false, payload is used as-is +// +// Returns the constructed signing input in the format: base64(header).base64(payload) or base64(header).payload +func SignBuffer(buf, hdr, payload []byte, encoder base64.Encoder, encodePayload bool) []byte { + l := encoder.EncodedLen(len(hdr)+len(payload)) + 1 + if cap(buf) < l { + buf = make([]byte, 0, l) + } + buf = buf[:0] + buf = encoder.AppendEncode(buf, hdr) + buf = append(buf, tokens.Period) + if encodePayload { + buf = encoder.AppendEncode(buf, payload) + } else { + buf = append(buf, payload...) + } + + return buf +} + +// AppendSignature appends a base64-encoded signature to a JWS signing input buffer. +// This completes the compact JWS serialization by adding the final signature component. +// The input buffer should contain the signing input (header.payload), and this function +// adds the period separator and base64-encoded signature. +// +// Parameters: +// - buf: Buffer containing the signing input (typically from SignBuffer) +// - signature: Raw signature bytes (will be base64-encoded) +// - encoder: Base64 encoder to use for encoding the signature +// +// Returns the complete compact JWS in the format: base64(header).base64(payload).base64(signature) +func AppendSignature(buf, signature []byte, encoder base64.Encoder) []byte { + l := len(buf) + len(signature) + 1 + if cap(buf) < l { + buf = make([]byte, 0, l) + } + buf = append(buf, tokens.Period) + buf = encoder.AppendEncode(buf, signature) + + return buf +} + +// JoinCompact creates a complete compact JWS serialization from individual components. +// This is a one-step function that combines header, payload, and signature into the final JWS format. +// It includes safety checks to prevent excessive memory allocation. +// +// Parameters: +// - buf: Reusable buffer (can be nil for automatic allocation) +// - hdr: Raw header bytes (will be base64-encoded) +// - payload: Raw payload bytes (encoded based on encodePayload flag) +// - signature: Raw signature bytes (will be base64-encoded) +// - encoder: Base64 encoder to use for encoding all components +// - encodePayload: If true, payload is base64-encoded; if false, payload is used as-is +// +// Returns the complete compact JWS or an error if the total size exceeds safety limits (1GB). +func JoinCompact(buf, hdr, payload, signature []byte, encoder base64.Encoder, encodePayload bool) ([]byte, error) { + const MaxBufferSize = 1 << 30 // 1 GB + totalSize := len(hdr) + len(payload) + len(signature) + 2 + if totalSize > MaxBufferSize { + return nil, errors.New("input sizes exceed maximum allowable buffer size") + } + if cap(buf) < totalSize { + buf = make([]byte, 0, totalSize) + } + buf = buf[:0] + buf = encoder.AppendEncode(buf, hdr) + buf = append(buf, tokens.Period) + if encodePayload { + buf = encoder.AppendEncode(buf, payload) + } else { + buf = append(buf, payload...) + } + buf = append(buf, tokens.Period) + buf = encoder.AppendEncode(buf, signature) + + return buf, nil +} + +var compactDelim = []byte{tokens.Period} + +var errInvalidNumberOfSegments = errors.New(`jwsbb: invalid number of segments`) + +// InvalidNumberOfSegmentsError returns the standard error for invalid JWS segment count. +// A valid compact JWS must have exactly 3 segments separated by periods: header.payload.signature +func InvalidNumberOfSegmentsError() error { + return errInvalidNumberOfSegments +} + +// SplitCompact parses a compact JWS serialization into its three components. +// This function validates that the input has exactly 3 segments separated by periods +// and returns the base64-encoded components without decoding them. +// +// Parameters: +// - src: Complete compact JWS string as bytes +// +// Returns: +// - protected: Base64-encoded protected header +// - payload: Base64-encoded payload (or raw payload if b64=false was used) +// - signature: Base64-encoded signature +// - err: Error if the format is invalid or segment count is wrong +func SplitCompact(src []byte) (protected, payload, signature []byte, err error) { + var s []byte + var ok bool + + protected, s, ok = bytes.Cut(src, compactDelim) + if !ok { // no period found + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + payload, s, ok = bytes.Cut(s, compactDelim) + if !ok { // only one period found + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + signature, _, ok = bytes.Cut(s, compactDelim) + if ok { // three periods found + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + return protected, payload, signature, nil +} + +// SplitCompactString is a convenience wrapper around SplitCompact for string inputs. +// It converts the string to bytes and parses the compact JWS serialization. +// +// Parameters: +// - src: Complete compact JWS as a string +// +// Returns the same components as SplitCompact: protected header, payload, signature, and error. +func SplitCompactString(src string) (protected, payload, signature []byte, err error) { + return SplitCompact([]byte(src)) +} + +// SplitCompactReader parses a compact JWS serialization from an io.Reader. +// This function handles both finite and streaming sources efficiently. +// For finite sources, it reads all data at once. For streaming sources, +// it uses a buffer-based approach to find segment boundaries. +// +// Parameters: +// - rdr: Reader containing the compact JWS data +// +// Returns: +// - protected: Base64-encoded protected header +// - payload: Base64-encoded payload (or raw payload if b64=false was used) +// - signature: Base64-encoded signature +// - err: Error if reading fails or the format is invalid +// +// The function validates that exactly 3 segments are present, separated by periods. +func SplitCompactReader(rdr io.Reader) (protected, payload, signature []byte, err error) { + data, err := jwxio.ReadAllFromFiniteSource(rdr) + if err == nil { + return SplitCompact(data) + } + + if !errors.Is(err, jwxio.NonFiniteSourceError()) { + return nil, nil, nil, err + } + + var periods int + var state int + + buf := make([]byte, 4096) + var sofar []byte + + for { + // read next bytes + n, err := rdr.Read(buf) + // return on unexpected read error + if err != nil && err != io.EOF { + return nil, nil, nil, io.ErrUnexpectedEOF + } + + // append to current buffer + sofar = append(sofar, buf[:n]...) + // loop to capture multiple tokens.Period in current buffer + for loop := true; loop; { + var i = bytes.IndexByte(sofar, tokens.Period) + if i == -1 && err != io.EOF { + // no tokens.Period found -> exit and read next bytes (outer loop) + loop = false + continue + } else if i == -1 && err == io.EOF { + // no tokens.Period found -> process rest and exit + i = len(sofar) + loop = false + } else { + // tokens.Period found + periods++ + } + + // Reaching this point means we have found a tokens.Period or EOF and process the rest of the buffer + switch state { + case 0: + protected = sofar[:i] + state++ + case 1: + payload = sofar[:i] + state++ + case 2: + signature = sofar[:i] + } + // Shorten current buffer + if len(sofar) > i { + sofar = sofar[i+1:] + } + } + // Exit on EOF + if err == io.EOF { + break + } + } + if periods != 2 { + return nil, nil, nil, InvalidNumberOfSegmentsError() + } + + return protected, payload, signature, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/header.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/header.go new file mode 100644 index 0000000000..d50c38eeb1 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/header.go @@ -0,0 +1,222 @@ +package jwsbb + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/valyala/fastjson" +) + +type headerNotFoundError struct { + key string +} + +func (e headerNotFoundError) Error() string { + return fmt.Sprintf(`jwsbb: header "%s" not found`, e.key) +} + +func (e headerNotFoundError) Is(target error) bool { + switch target.(type) { + case headerNotFoundError, *headerNotFoundError: + // If the target is a headerNotFoundError or a pointer to it, we + // consider it a match + return true + default: + return false + } +} + +// ErrHeaderdNotFound returns an error that can be passed to `errors.Is` to check if the error is +// the result of the field not being found +func ErrHeaderNotFound() error { + return headerNotFoundError{} +} + +// ErrFieldNotFound is an alias for ErrHeaderNotFound, and is deprecated. It was a misnomer. +// It will be removed in a future release. +func ErrFieldNotFound() error { + return ErrHeaderNotFound() +} + +// Header is an object that allows you to access the JWS header in a quick and +// dirty way. It does not verify anything, it does not know anything about what +// each header field means, and it does not care about the JWS specification. +// But when you need to access the JWS header for that one field that you +// need, this is the object you want to use. +// +// As of this writing, HeaderParser cannot be used from concurrent goroutines. +// You will need to create a new instance for each goroutine that needs to parse a JWS header. +// Also, in general values obtained from this object should only be used +// while the Header object is still in scope. +// +// This type is experimental and may change or be removed in the future. +type Header interface { + // I'm hiding this behind an interface so that users won't accidentally + // rely on the underlying json handler implementation, nor the concrete + // type name that jwsbb provides, as we may choose a different one in the future. + jwsbbHeader() +} + +type header struct { + v *fastjson.Value + err error +} + +func (h *header) jwsbbHeader() {} + +// HeaderParseCompact parses a JWS header from a compact serialization format. +// You will need to call HeaderGet* functions to extract the values from the header. +// +// This function is experimental and may change or be removed in the future. +func HeaderParseCompact(buf []byte) Header { + decoded, err := base64.Decode(buf) + if err != nil { + return &header{err: err} + } + return HeaderParse(decoded) +} + +// HeaderParse parses a JWS header from a byte slice containing the decoded JSON. +// You will need to call HeaderGet* functions to extract the values from the header. +// +// Unlike HeaderParseCompact, this function does not perform any base64 decoding. +// This function is experimental and may change or be removed in the future. +func HeaderParse(decoded []byte) Header { + var p fastjson.Parser + v, err := p.ParseBytes(decoded) + if err != nil { + return &header{err: err} + } + return &header{ + v: v, + } +} + +func headerGet(h Header, key string) (*fastjson.Value, error) { + //nolint:forcetypeassert + hh := h.(*header) // we _know_ this can't be another type + if hh.err != nil { + return nil, hh.err + } + + v := hh.v.Get(key) + if v == nil { + return nil, headerNotFoundError{key: key} + } + return v, nil +} + +// HeaderGetString returns the string value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a string. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetString(h Header, key string) (string, error) { + v, err := headerGet(h, key) + if err != nil { + return "", err + } + + sb, err := v.StringBytes() + if err != nil { + return "", err + } + + return string(sb), nil +} + +// HeaderGetBool returns the boolean value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a boolean. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetBool(h Header, key string) (bool, error) { + v, err := headerGet(h, key) + if err != nil { + return false, err + } + return v.Bool() +} + +// HeaderGetFloat64 returns the float64 value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a float64. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetFloat64(h Header, key string) (float64, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Float64() +} + +// HeaderGetInt returns the int value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not an int. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetInt(h Header, key string) (int, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Int() +} + +// HeaderGetInt64 returns the int64 value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not an int64. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetInt64(h Header, key string) (int64, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Int64() +} + +// HeaderGetStringBytes returns the byte slice value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a byte slice. +// +// Because of limitations of the underlying library, you cannot use the return value +// of this function after the parser is garbage collected. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetStringBytes(h Header, key string) ([]byte, error) { + v, err := headerGet(h, key) + if err != nil { + return nil, err + } + + return v.StringBytes() +} + +// HeaderGetUint returns the uint value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a uint. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetUint(h Header, key string) (uint, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + return v.Uint() +} + +// HeaderGetUint64 returns the uint64 value for the given key from the JWS header. +// An error is returned if the JSON was not valid, if the key does not exist, +// or if the value is not a uint64. +// +// This function is experimental and may change or be removed in the future. +func HeaderGetUint64(h Header, key string) (uint64, error) { + v, err := headerGet(h, key) + if err != nil { + return 0, err + } + + return v.Uint64() +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/hmac.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/hmac.go new file mode 100644 index 0000000000..782915ff2a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/hmac.go @@ -0,0 +1,67 @@ +package jwsbb + +import ( + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" +) + +var hmacHashFuncs = map[string]func() hash.Hash{ + "HS256": sha256.New, + "HS384": sha512.New384, + "HS512": sha512.New, +} + +func isSupportedHMACAlgorithm(alg string) bool { + _, ok := hmacHashFuncs[alg] + return ok +} + +// HMACHashFuncFor returns the appropriate hash function for the given HMAC algorithm. +// Supported algorithms: HS256 (SHA-256), HS384 (SHA-384), HS512 (SHA-512). +// Returns the hash function constructor and an error if the algorithm is unsupported. +func HMACHashFuncFor(alg string) (func() hash.Hash, error) { + if h, ok := hmacHashFuncs[alg]; ok { + return h, nil + } + return nil, fmt.Errorf("unsupported HMAC algorithm %s", alg) +} + +func toHMACKey(dst *[]byte, key any) error { + if err := keyconv.ByteSliceKey(dst, key); err != nil { + return fmt.Errorf(`jws.toHMACKey: invalid key type %T. []byte is required: %w`, key, err) + } + + if len(*dst) == 0 { + return fmt.Errorf(`jws.toHMACKey: missing key while signing payload`) + } + return nil +} + +// SignHMAC generates an HMAC signature for the given payload using the specified hash function and key. +// The raw parameter should be the pre-computed signing input (typically header.payload). +func SignHMAC(key, payload []byte, hfunc func() hash.Hash) ([]byte, error) { + h := hmac.New(hfunc, key) + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using hmac: %w`, err) + } + return h.Sum(nil), nil +} + +// VerifyHMAC verifies an HMAC signature for the given payload. +// This function verifies the signature using the specified key and hash function. +// The payload parameter should be the pre-computed signing input (typically header.payload). +func VerifyHMAC(key, payload, signature []byte, hfunc func() hash.Hash) error { + expected, err := SignHMAC(key, payload, hfunc) + if err != nil { + return fmt.Errorf("failed to sign payload for verification: %w", err) + } + if !hmac.Equal(signature, expected) { + return fmt.Errorf("invalid HMAC signature") + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/jwsbb.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/jwsbb.go new file mode 100644 index 0000000000..51d01df63f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/jwsbb.go @@ -0,0 +1,29 @@ +// Package jwsbb provides the building blocks (hence the name "bb") for JWS operations. +// It should be thought of as a low-level API, almost akin to internal packages +// that should not be used directly by users of the jwx package. However, these exist +// to provide a more efficient way to perform JWS operations without the overhead of +// the higher-level jws package to power-users who know what they are doing. +// +// This package is currently considered EXPERIMENTAL, and the API may change +// without notice. It is not recommended to use this package unless you are +// fully aware of the implications of using it. +// +// All bb packages in jwx follow the same design principles: +// 1. Does minimal checking of input parameters (for performance); callers need to ensure that the parameters are valid. +// 2. All exported functions are strongly typed (i.e. they do not take `any` types unless they absolutely have to). +// 3. Does not rely on other public jwx packages (they are standalone, except for internal packages). +package jwsbb + +// Signer is a generic interface that defines the method for signing payloads. +// The type parameter K represents the key type (e.g., []byte for HMAC keys, +// *rsa.PrivateKey for RSA keys, *ecdsa.PrivateKey for ECDSA keys). +type Signer[K any] interface { + Sign(key K, payload []byte) ([]byte, error) +} + +// Verifier is a generic interface that defines the method for verifying signatures. +// The type parameter K represents the key type (e.g., []byte for HMAC keys, +// *rsa.PublicKey for RSA keys, *ecdsa.PublicKey for ECDSA keys). +type Verifier[K any] interface { + Verify(key K, buf []byte, signature []byte) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/rsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/rsa.go new file mode 100644 index 0000000000..f3083dcea9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/rsa.go @@ -0,0 +1,86 @@ +package jwsbb + +import ( + "crypto" + "crypto/rsa" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +func rsaGetSignerCryptoSignerKey(key any) (crypto.Signer, bool, error) { + cs, isCryptoSigner := key.(crypto.Signer) + if isCryptoSigner { + if !keytype.IsValidRSAKey(key) { + return nil, false, fmt.Errorf(`cannot use key of type %T`, key) + } + return cs, true, nil + } + return nil, false, nil +} + +var rsaHashFuncs = map[string]struct { + Hash crypto.Hash + PSS bool // whether to use PSS padding +}{ + "RS256": {Hash: crypto.SHA256, PSS: false}, + "RS384": {Hash: crypto.SHA384, PSS: false}, + "RS512": {Hash: crypto.SHA512, PSS: false}, + "PS256": {Hash: crypto.SHA256, PSS: true}, + "PS384": {Hash: crypto.SHA384, PSS: true}, + "PS512": {Hash: crypto.SHA512, PSS: true}, +} + +func isSuppotedRSAAlgorithm(alg string) bool { + _, ok := rsaHashFuncs[alg] + return ok +} + +// RSAHashFuncFor returns the appropriate hash function and PSS flag for the given RSA algorithm. +// Supported algorithms: RS256, RS384, RS512 (PKCS#1 v1.5) and PS256, PS384, PS512 (PSS). +// Returns the hash function, PSS flag, and an error if the algorithm is unsupported. +func RSAHashFuncFor(alg string) (crypto.Hash, bool, error) { + if h, ok := rsaHashFuncs[alg]; ok { + return h.Hash, h.PSS, nil + } + return 0, false, fmt.Errorf("unsupported RSA algorithm %s", alg) +} + +// RSAPSSOptions returns the PSS options for RSA-PSS signatures with the specified hash. +// The salt length is set to equal the hash length as per RFC 7518. +func RSAPSSOptions(h crypto.Hash) rsa.PSSOptions { + return rsa.PSSOptions{ + Hash: h, + SaltLength: rsa.PSSSaltLengthEqualsHash, + } +} + +// SignRSA generates an RSA signature for the given payload using the specified private key and options. +// The raw parameter should be the pre-computed signing input (typically header.payload). +// If pss is true, RSA-PSS is used; otherwise, PKCS#1 v1.5 is used. +// +// The rr parameter is an optional io.Reader that can be used to provide randomness for signing. +// If rr is nil, it defaults to rand.Reader. +func SignRSA(key *rsa.PrivateKey, payload []byte, h crypto.Hash, pss bool, rr io.Reader) ([]byte, error) { + var opts crypto.SignerOpts = h + if pss { + rsaopts := RSAPSSOptions(h) + opts = &rsaopts + } + return cryptosign(key, payload, h, opts, rr) +} + +// VerifyRSA verifies an RSA signature for the given payload and header. +// This function constructs the signing input by encoding the header and payload according to JWS specification, +// then verifies the signature using the specified public key and hash algorithm. +// If pss is true, RSA-PSS verification is used; otherwise, PKCS#1 v1.5 verification is used. +func VerifyRSA(key *rsa.PublicKey, payload, signature []byte, h crypto.Hash, pss bool) error { + hasher := h.New() + hasher.Write(payload) + digest := hasher.Sum(nil) + if pss { + return rsa.VerifyPSS(key, h, digest, signature, &rsa.PSSOptions{Hash: h, SaltLength: rsa.PSSSaltLengthEqualsHash}) + } + return rsa.VerifyPKCS1v15(key, h, digest, signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/sign.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/sign.go new file mode 100644 index 0000000000..0599ee5dff --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/sign.go @@ -0,0 +1,95 @@ +package jwsbb + +import ( + "crypto" + "crypto/rsa" + "fmt" + "io" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" +) + +// Sign generates a JWS signature using the specified key and algorithm. +// +// This function loads the signer registered in the hwsbb package _ONLY_. +// It does not support custom signers that the user might have registered. +// +// rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. +// Not all algorithms require this parameter, but it is included for consistency. +// 99% of the time, you can pass nil for rr, and it will work fine. +func Sign(key any, alg string, payload []byte, rr io.Reader) ([]byte, error) { + switch { + case isSupportedHMACAlgorithm(alg): + return dispatchHMACSign(key, alg, payload) + case isSuppotedRSAAlgorithm(alg): + return dispatchRSASign(key, alg, payload, rr) + case isSuppotedECDSAAlgorithm(alg): + return dispatchECDSASign(key, alg, payload, rr) + case isSupportedEdDSAAlgorithm(alg): + return dispatchEdDSASign(key, alg, payload, rr) + } + + return nil, fmt.Errorf(`jwsbb.Sign: unsupported signature algorithm %q`, alg) +} + +func dispatchHMACSign(key any, alg string, payload []byte) ([]byte, error) { + h, err := HMACHashFuncFor(alg) + if err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: failed to get hash function for %s: %w`, alg, err) + } + + var hmackey []byte + if err := toHMACKey(&hmackey, key); err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: %w`, err) + } + return SignHMAC(hmackey, payload, h) +} + +func dispatchRSASign(key any, alg string, payload []byte, rr io.Reader) ([]byte, error) { + h, pss, err := RSAHashFuncFor(alg) + if err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: failed to get hash function for %s: %w`, alg, err) + } + cs, isCryptoSigner, err := rsaGetSignerCryptoSignerKey(key) + if err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: %w`, err) + } + if isCryptoSigner { + var options crypto.SignerOpts = h + if pss { + rsaopts := RSAPSSOptions(h) + options = &rsaopts + } + return SignCryptoSigner(cs, payload, h, options, rr) + } + + var privkey *rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`jws.RSASigner: invalid key type %T. rsa.PrivateKey is required: %w`, key, err) + } + return SignRSA(privkey, payload, h, pss, rr) +} + +func dispatchEdDSASign(key any, _ string, payload []byte, rr io.Reader) ([]byte, error) { + signer, err := eddsaGetSigner(key) + if err != nil { + return nil, fmt.Errorf(`jws.EdDSASigner: %w`, err) + } + + return SignCryptoSigner(signer, payload, crypto.Hash(0), crypto.Hash(0), rr) +} + +func dispatchECDSASign(key any, alg string, payload []byte, rr io.Reader) ([]byte, error) { + h, err := ECDSAHashFuncFor(alg) + if err != nil { + return nil, fmt.Errorf(`jwsbb.Sign: failed to get hash function for %s: %w`, alg, err) + } + privkey, cs, isCryptoSigner, err := ecdsaGetSignerKey(key) + if err != nil { + return nil, fmt.Errorf(`jws.ECDSASigner: %w`, err) + } + if isCryptoSigner { + return SignECDSACryptoSigner(cs, payload, h, rr) + } + return SignECDSA(privkey, payload, h, rr) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/verify.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/verify.go new file mode 100644 index 0000000000..85121199fd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/jwsbb/verify.go @@ -0,0 +1,127 @@ +package jwsbb + +import ( + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" +) + +// Verify verifies a JWS signature using the specified key and algorithm. +// +// This function loads the verifier registered in the jwsbb package _ONLY_. +// It does not support custom verifiers that the user might have registered. +func Verify(key any, alg string, payload, signature []byte) error { + switch { + case isSupportedHMACAlgorithm(alg): + return dispatchHMACVerify(key, alg, payload, signature) + case isSuppotedRSAAlgorithm(alg): + return dispatchRSAVerify(key, alg, payload, signature) + case isSuppotedECDSAAlgorithm(alg): + return dispatchECDSAVerify(key, alg, payload, signature) + case isSupportedEdDSAAlgorithm(alg): + return dispatchEdDSAVerify(key, alg, payload, signature) + } + + return fmt.Errorf(`jwsbb.Verify: unsupported signature algorithm %q`, alg) +} + +func dispatchHMACVerify(key any, alg string, payload, signature []byte) error { + h, err := HMACHashFuncFor(alg) + if err != nil { + return fmt.Errorf(`jwsbb.Verify: failed to get hash function for %s: %w`, alg, err) + } + + var hmackey []byte + if err := toHMACKey(&hmackey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: %w`, err) + } + return VerifyHMAC(hmackey, payload, signature, h) +} + +func dispatchRSAVerify(key any, alg string, payload, signature []byte) error { + h, pss, err := RSAHashFuncFor(alg) + if err != nil { + return fmt.Errorf(`jwsbb.Verify: failed to get hash function for %s: %w`, alg, err) + } + + var pubkey *rsa.PublicKey + + if cs, ok := key.(crypto.Signer); ok { + cpub := cs.Public() + switch cpub := cpub.(type) { + case rsa.PublicKey: + pubkey = &cpub + case *rsa.PublicKey: + pubkey = cpub + default: + return fmt.Errorf(`jwsbb.Verify: failed to retrieve rsa.PublicKey out of crypto.Signer %T`, key) + } + } else { + if err := keyconv.RSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: failed to retrieve rsa.PublicKey out of %T: %w`, key, err) + } + } + + return VerifyRSA(pubkey, payload, signature, h, pss) +} + +func dispatchECDSAVerify(key any, alg string, payload, signature []byte) error { + h, err := ECDSAHashFuncFor(alg) + if err != nil { + return fmt.Errorf(`jwsbb.Verify: failed to get hash function for %s: %w`, alg, err) + } + + pubkey, cs, isCryptoSigner, err := ecdsaGetVerifierKey(key) + if err != nil { + return fmt.Errorf(`jwsbb.Verify: %w`, err) + } + if isCryptoSigner { + return VerifyECDSACryptoSigner(cs, payload, signature, h) + } + return VerifyECDSA(pubkey, payload, signature, h) +} + +func dispatchEdDSAVerify(key any, _ string, payload, signature []byte) error { + var pubkey ed25519.PublicKey + signer, ok := key.(crypto.Signer) + if ok { + v := signer.Public() + pubkey, ok = v.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`jwsbb.Verify: expected crypto.Signer.Public() to return ed25519.PublicKey, but got %T`, v) + } + } else { + if err := keyconv.Ed25519PublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`jwsbb.Verify: failed to retrieve ed25519.PublicKey out of %T: %w`, key, err) + } + } + + return VerifyEdDSA(pubkey, payload, signature) +} + +func ecdsaGetVerifierKey(key any) (*ecdsa.PublicKey, crypto.Signer, bool, error) { + cs, isCryptoSigner := key.(crypto.Signer) + if isCryptoSigner { + switch key.(type) { + case ecdsa.PublicKey, *ecdsa.PublicKey: + // if it's ecdsa.PublicKey, it's more efficient to + // go through the non-crypto.Signer route. Set isCryptoSigner to false + isCryptoSigner = false + } + } + + if isCryptoSigner { + return nil, cs, true, nil + } + + var pubkey *ecdsa.PublicKey + if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil { + return nil, nil, false, fmt.Errorf(`invalid key type %T. ecdsa.PublicKey is required: %w`, key, err) + } + + return pubkey, nil, false, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/key_provider.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/key_provider.go new file mode 100644 index 0000000000..84529a1a87 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/key_provider.go @@ -0,0 +1,291 @@ +package jws + +import ( + "context" + "fmt" + "net/url" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" +) + +// KeyProvider is responsible for providing key(s) to sign or verify a payload. +// Multiple `jws.KeyProvider`s can be passed to `jws.Verify()` or `jws.Sign()` +// +// `jws.Sign()` can only accept static key providers via `jws.WithKey()`, +// while `jws.Verify()` can accept `jws.WithKey()`, `jws.WithKeySet()`, +// `jws.WithVerifyAuto()`, and `jws.WithKeyProvider()`. +// +// Understanding how this works is crucial to learn how this package works. +// +// `jws.Sign()` is straightforward: signatures are created for each +// provided key. +// +// `jws.Verify()` is a bit more involved, because there are cases you +// will want to compute/deduce/guess the keys that you would like to +// use for verification. +// +// The first thing that `jws.Verify()` does is to collect the +// KeyProviders from the option list that the user provided (presented in pseudocode): +// +// keyProviders := filterKeyProviders(options) +// +// Then, remember that a JWS message may contain multiple signatures in the +// message. For each signature, we call on the KeyProviders to give us +// the key(s) to use on this signature: +// +// for sig in msg.Signatures { +// for kp in keyProviders { +// kp.FetchKeys(ctx, sink, sig, msg) +// ... +// } +// } +// +// The `sink` argument passed to the KeyProvider is a temporary storage +// for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` +// is responsible for sending keys into the `sink`. +// +// When called, the `KeyProvider` created by `jws.WithKey()` sends the same key, +// `jws.WithKeySet()` sends keys that matches a particular `kid` and `alg`, +// `jws.WithVerifyAuto()` fetches a JWK from the `jku` URL, +// and finally `jws.WithKeyProvider()` allows you to execute arbitrary +// logic to provide keys. If you are providing a custom `KeyProvider`, +// you should execute the necessary checks or retrieval of keys, and +// then send the key(s) to the sink: +// +// sink.Key(alg, key) +// +// These keys are then retrieved and tried for each signature, until +// a match is found: +// +// keys := sink.Keys() +// for key in keys { +// if givenSignature == makeSignature(key, payload, ...)) { +// return OK +// } +// } +type KeyProvider interface { + FetchKeys(context.Context, KeySink, *Signature, *Message) error +} + +// KeySink is a data storage where `jws.KeyProvider` objects should +// send their keys to. +type KeySink interface { + Key(jwa.SignatureAlgorithm, any) +} + +type algKeyPair struct { + alg jwa.KeyAlgorithm + key any +} + +type algKeySink struct { + mu sync.Mutex + list []algKeyPair +} + +func (s *algKeySink) Key(alg jwa.SignatureAlgorithm, key any) { + s.mu.Lock() + s.list = append(s.list, algKeyPair{alg, key}) + s.mu.Unlock() +} + +type staticKeyProvider struct { + alg jwa.SignatureAlgorithm + key any +} + +func (kp *staticKeyProvider) FetchKeys(_ context.Context, sink KeySink, _ *Signature, _ *Message) error { + sink.Key(kp.alg, kp.key) + return nil +} + +type keySetProvider struct { + set jwk.Set + requireKid bool // true if `kid` must be specified + useDefault bool // true if the first key should be used iff there's exactly one key in set + inferAlgorithm bool // true if the algorithm should be inferred from key type + multipleKeysPerKeyID bool // true if we should attempt to match multiple keys per key ID. if false we assume that only one key exists for a given key ID +} + +func (kp *keySetProvider) selectKey(sink KeySink, key jwk.Key, sig *Signature, _ *Message) error { + if usage, ok := key.KeyUsage(); ok { + // it's okay if use: "". we'll assume it's "sig" + if usage != "" && usage != jwk.ForSignature.String() { + return nil + } + } + + if v, ok := key.Algorithm(); ok { + salg, ok := jwa.LookupSignatureAlgorithm(v.String()) + if !ok { + return fmt.Errorf(`invalid signature algorithm %q`, v) + } + + sink.Key(salg, key) + return nil + } + + if kp.inferAlgorithm { + algs, err := AlgorithmsForKey(key) + if err != nil { + return fmt.Errorf(`failed to get a list of signature methods for key type %s: %w`, key.KeyType(), err) + } + + // bail out if the JWT has a `alg` field, and it doesn't match + if tokAlg, ok := sig.ProtectedHeaders().Algorithm(); ok { + for _, alg := range algs { + if tokAlg == alg { + sink.Key(alg, key) + return nil + } + } + return fmt.Errorf(`algorithm in the message does not match any of the inferred algorithms`) + } + + // Yes, you get to try them all!!!!!!! + for _, alg := range algs { + sink.Key(alg, key) + } + return nil + } + return nil +} + +func (kp *keySetProvider) FetchKeys(_ context.Context, sink KeySink, sig *Signature, msg *Message) error { + if kp.requireKid { + wantedKid, ok := sig.ProtectedHeaders().KeyID() + if !ok { + // If the kid is NOT specified... kp.useDefault needs to be true, and the + // JWKs must have exactly one key in it + if !kp.useDefault { + return fmt.Errorf(`failed to find matching key: no key ID ("kid") specified in token`) + } else if kp.useDefault && kp.set.Len() > 1 { + return fmt.Errorf(`failed to find matching key: no key ID ("kid") specified in token but multiple keys available in key set`) + } + + // if we got here, then useDefault == true AND there is exactly + // one key in the set. + key, ok := kp.set.Key(0) + if !ok { + return fmt.Errorf(`failed to get key at index 0 (empty JWKS?)`) + } + return kp.selectKey(sink, key, sig, msg) + } + + // Otherwise we better be able to look up the key. + // <= v2.0.3 backwards compatible case: only match a single key + // whose key ID matches `wantedKid` + if !kp.multipleKeysPerKeyID { + key, ok := kp.set.LookupKeyID(wantedKid) + if !ok { + return fmt.Errorf(`failed to find key with key ID %q in key set`, wantedKid) + } + return kp.selectKey(sink, key, sig, msg) + } + + // if multipleKeysPerKeyID is true, we attempt all keys whose key ID matches + // the wantedKey + ok = false + for i := range kp.set.Len() { + key, _ := kp.set.Key(i) + if kid, ok := key.KeyID(); !ok || kid != wantedKid { + continue + } + + if err := kp.selectKey(sink, key, sig, msg); err != nil { + continue + } + ok = true + // continue processing so that we try all keys with the same key ID + } + if !ok { + return fmt.Errorf(`failed to find key with key ID %q in key set`, wantedKid) + } + return nil + } + + // Otherwise just try all keys + for i := range kp.set.Len() { + key, ok := kp.set.Key(i) + if !ok { + return fmt.Errorf(`failed to get key at index %d`, i) + } + if err := kp.selectKey(sink, key, sig, msg); err != nil { + continue + } + } + return nil +} + +type jkuProvider struct { + fetcher jwk.Fetcher + options []jwk.FetchOption +} + +func (kp jkuProvider) FetchKeys(ctx context.Context, sink KeySink, sig *Signature, _ *Message) error { + if kp.fetcher == nil { + kp.fetcher = jwk.FetchFunc(jwk.Fetch) + } + + kid, ok := sig.ProtectedHeaders().KeyID() + if !ok { + return fmt.Errorf(`use of "jku" requires that the payload contain a "kid" field in the protected header`) + } + + // errors here can't be reliably passed to the consumers. + // it's unfortunate, but if you need this control, you are + // going to have to write your own fetcher + u, ok := sig.ProtectedHeaders().JWKSetURL() + if !ok || u == "" { + return fmt.Errorf(`use of "jku" field specified, but the field is empty`) + } + uo, err := url.Parse(u) + if err != nil { + return fmt.Errorf(`failed to parse "jku": %w`, err) + } + if uo.Scheme != "https" { + return fmt.Errorf(`url in "jku" must be HTTPS`) + } + + set, err := kp.fetcher.Fetch(ctx, u, kp.options...) + if err != nil { + return fmt.Errorf(`failed to fetch %q: %w`, u, err) + } + + key, ok := set.LookupKeyID(kid) + if !ok { + // It is not an error if the key with the kid doesn't exist + return nil + } + + algs, err := AlgorithmsForKey(key) + if err != nil { + return fmt.Errorf(`failed to get a list of signature methods for key type %s: %w`, key.KeyType(), err) + } + + hdrAlg, ok := sig.ProtectedHeaders().Algorithm() + if ok { + for _, alg := range algs { + // if we have an "alg" field in the JWS, we can only proceed if + // the inferred algorithm matches + if hdrAlg != alg { + continue + } + + sink.Key(alg, key) + break + } + } + return nil +} + +// KeyProviderFunc is a type of KeyProvider that is implemented by +// a single function. You can use this to create ad-hoc `KeyProvider` +// instances. +type KeyProviderFunc func(context.Context, KeySink, *Signature, *Message) error + +func (kp KeyProviderFunc) FetchKeys(ctx context.Context, sink KeySink, sig *Signature, msg *Message) error { + return kp(ctx, sink, sig, msg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy.go new file mode 100644 index 0000000000..a6687d68cb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy.go @@ -0,0 +1,88 @@ +package jws + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/legacy" +) + +func enableLegacySigners() { + for _, alg := range []jwa.SignatureAlgorithm{jwa.HS256(), jwa.HS384(), jwa.HS512()} { + if err := RegisterSigner(alg, func(alg jwa.SignatureAlgorithm) SignerFactory { + return SignerFactoryFn(func() (Signer, error) { + return legacy.NewHMACSigner(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(alg, func(alg jwa.SignatureAlgorithm) VerifierFactory { + return VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewHMACVerifier(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } + } + + for _, alg := range []jwa.SignatureAlgorithm{jwa.RS256(), jwa.RS384(), jwa.RS512(), jwa.PS256(), jwa.PS384(), jwa.PS512()} { + if err := RegisterSigner(alg, func(alg jwa.SignatureAlgorithm) SignerFactory { + return SignerFactoryFn(func() (Signer, error) { + return legacy.NewRSASigner(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(alg, func(alg jwa.SignatureAlgorithm) VerifierFactory { + return VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewRSAVerifier(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } + } + for _, alg := range []jwa.SignatureAlgorithm{jwa.ES256(), jwa.ES384(), jwa.ES512(), jwa.ES256K()} { + if err := RegisterSigner(alg, func(alg jwa.SignatureAlgorithm) SignerFactory { + return SignerFactoryFn(func() (Signer, error) { + return legacy.NewECDSASigner(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(alg, func(alg jwa.SignatureAlgorithm) VerifierFactory { + return VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewECDSAVerifier(alg), nil + }) + }(alg)); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } + } + + if err := RegisterSigner(jwa.EdDSA(), SignerFactoryFn(func() (Signer, error) { + return legacy.NewEdDSASigner(), nil + })); err != nil { + panic(fmt.Sprintf("RegisterSigner failed: %v", err)) + } + if err := RegisterVerifier(jwa.EdDSA(), VerifierFactoryFn(func() (Verifier, error) { + return legacy.NewEdDSAVerifier(), nil + })); err != nil { + panic(fmt.Sprintf("RegisterVerifier failed: %v", err)) + } +} + +func legacySignerFor(alg jwa.SignatureAlgorithm) (Signer, error) { + muSigner.Lock() + s, ok := signers[alg] + if !ok { + v, err := NewSigner(alg) + if err != nil { + muSigner.Unlock() + return nil, fmt.Errorf(`failed to create payload signer: %w`, err) + } + signers[alg] = v + s = v + } + muSigner.Unlock() + + return s, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/BUILD.bazel new file mode 100644 index 0000000000..8e77cece46 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "legacy", + srcs = [ + "ecdsa.go", + "eddsa.go", + "hmac.go", + "legacy.go", + "rsa.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jws/legacy", + visibility = ["//visibility:public"], + deps = [ + "//internal/ecutil", + "//internal/keyconv", + "//internal/pool", + "//jwa", + "//jws/internal/keytype", + ], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/ecdsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/ecdsa.go new file mode 100644 index 0000000000..0b714a44b8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/ecdsa.go @@ -0,0 +1,204 @@ +package legacy + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "encoding/asn1" + "fmt" + "math/big" + + "github.com/lestrrat-go/jwx/v3/internal/ecutil" + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +var ecdsaSigners = make(map[jwa.SignatureAlgorithm]*ecdsaSigner) +var ecdsaVerifiers = make(map[jwa.SignatureAlgorithm]*ecdsaVerifier) + +func init() { + algs := map[jwa.SignatureAlgorithm]crypto.Hash{ + jwa.ES256(): crypto.SHA256, + jwa.ES384(): crypto.SHA384, + jwa.ES512(): crypto.SHA512, + jwa.ES256K(): crypto.SHA256, + } + for alg, hash := range algs { + ecdsaSigners[alg] = &ecdsaSigner{ + alg: alg, + hash: hash, + } + ecdsaVerifiers[alg] = &ecdsaVerifier{ + alg: alg, + hash: hash, + } + } +} + +func NewECDSASigner(alg jwa.SignatureAlgorithm) Signer { + return ecdsaSigners[alg] +} + +// ecdsaSigners are immutable. +type ecdsaSigner struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash +} + +func (es ecdsaSigner) Algorithm() jwa.SignatureAlgorithm { + return es.alg +} + +func (es *ecdsaSigner) Sign(payload []byte, key any) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`missing private key while signing payload`) + } + + h := es.hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using ecdsa: %w`, err) + } + + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidECDSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate ECDSA based signatures`, key) + } + switch key.(type) { + case ecdsa.PrivateKey, *ecdsa.PrivateKey: + // if it's a ecdsa.PrivateKey, it's more efficient to + // go through the non-crypto.Signer route. Set ok to false + ok = false + } + } + + var r, s *big.Int + var curveBits int + if ok { + signed, err := signer.Sign(rand.Reader, h.Sum(nil), es.hash) + if err != nil { + return nil, err + } + + var p struct { + R *big.Int + S *big.Int + } + if _, err := asn1.Unmarshal(signed, &p); err != nil { + return nil, fmt.Errorf(`failed to unmarshal ASN1 encoded signature: %w`, err) + } + + // Okay, this is silly, but hear me out. When we use the + // crypto.Signer interface, the PrivateKey is hidden. + // But we need some information about the key (its bit size). + // + // So while silly, we're going to have to make another call + // here and fetch the Public key. + // This probably means that this should be cached some where. + cpub := signer.Public() + pubkey, ok := cpub.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey) + } + curveBits = pubkey.Curve.Params().BitSize + + r = p.R + s = p.S + } else { + var privkey ecdsa.PrivateKey + if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve ecdsa.PrivateKey out of %T: %w`, key, err) + } + curveBits = privkey.Curve.Params().BitSize + rtmp, stmp, err := ecdsa.Sign(rand.Reader, &privkey, h.Sum(nil)) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload using ecdsa: %w`, err) + } + r = rtmp + s = stmp + } + + keyBytes := curveBits / 8 + // Curve bits do not need to be a multiple of 8. + if curveBits%8 > 0 { + keyBytes++ + } + + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := s.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + out := append(rBytesPadded, sBytesPadded...) + + return out, nil +} + +// ecdsaVerifiers are immutable. +type ecdsaVerifier struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash +} + +func NewECDSAVerifier(alg jwa.SignatureAlgorithm) Verifier { + return ecdsaVerifiers[alg] +} + +func (v ecdsaVerifier) Algorithm() jwa.SignatureAlgorithm { + return v.alg +} + +func (v *ecdsaVerifier) Verify(payload []byte, signature []byte, key any) error { + if key == nil { + return fmt.Errorf(`missing public key while verifying payload`) + } + + var pubkey ecdsa.PublicKey + if cs, ok := key.(crypto.Signer); ok { + cpub := cs.Public() + switch cpub := cpub.(type) { + case ecdsa.PublicKey: + pubkey = cpub + case *ecdsa.PublicKey: + pubkey = *cpub + default: + return fmt.Errorf(`failed to retrieve ecdsa.PublicKey out of crypto.Signer %T`, key) + } + } else { + if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`failed to retrieve ecdsa.PublicKey out of %T: %w`, key, err) + } + } + + if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { + return fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`) + } + + r := pool.BigInt().Get() + s := pool.BigInt().Get() + defer pool.BigInt().Put(r) + defer pool.BigInt().Put(s) + + keySize := ecutil.CalculateKeySize(pubkey.Curve) + if len(signature) != keySize*2 { + return fmt.Errorf(`invalid signature length for curve %q`, pubkey.Curve.Params().Name) + } + + r.SetBytes(signature[:keySize]) + s.SetBytes(signature[keySize:]) + + h := v.hash.New() + if _, err := h.Write(payload); err != nil { + return fmt.Errorf(`failed to write payload using ecdsa: %w`, err) + } + + if !ecdsa.Verify(&pubkey, h.Sum(nil), r, s) { + return fmt.Errorf(`failed to verify signature using ecdsa`) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/eddsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/eddsa.go new file mode 100644 index 0000000000..289e48e3b3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/eddsa.go @@ -0,0 +1,79 @@ +package legacy + +import ( + "crypto" + "crypto/ed25519" + "crypto/rand" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +type eddsaSigner struct{} + +func NewEdDSASigner() Signer { + return &eddsaSigner{} +} + +func (s eddsaSigner) Algorithm() jwa.SignatureAlgorithm { + return jwa.EdDSA() +} + +func (s eddsaSigner) Sign(payload []byte, key any) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`missing private key while signing payload`) + } + + // The ed25519.PrivateKey object implements crypto.Signer, so we should + // simply accept a crypto.Signer here. + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidEDDSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate EdDSA based signatures`, key) + } + } else { + // This fallback exists for cases when jwk.Key was passed, or + // users gave us a pointer instead of non-pointer, etc. + var privkey ed25519.PrivateKey + if err := keyconv.Ed25519PrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve ed25519.PrivateKey out of %T: %w`, key, err) + } + signer = privkey + } + + return signer.Sign(rand.Reader, payload, crypto.Hash(0)) +} + +type eddsaVerifier struct{} + +func NewEdDSAVerifier() Verifier { + return &eddsaVerifier{} +} + +func (v eddsaVerifier) Verify(payload, signature []byte, key any) (err error) { + if key == nil { + return fmt.Errorf(`missing public key while verifying payload`) + } + + var pubkey ed25519.PublicKey + signer, ok := key.(crypto.Signer) + if ok { + v := signer.Public() + pubkey, ok = v.(ed25519.PublicKey) + if !ok { + return fmt.Errorf(`expected crypto.Signer.Public() to return ed25519.PublicKey, but got %T`, v) + } + } else { + if err := keyconv.Ed25519PublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`failed to retrieve ed25519.PublicKey out of %T: %w`, key, err) + } + } + + if !ed25519.Verify(pubkey, payload, signature) { + return fmt.Errorf(`failed to match EdDSA signature`) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/hmac.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/hmac.go new file mode 100644 index 0000000000..7a3c9d1896 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/hmac.go @@ -0,0 +1,90 @@ +package legacy + +import ( + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func init() { + algs := map[jwa.SignatureAlgorithm]func() hash.Hash{ + jwa.HS256(): sha256.New, + jwa.HS384(): sha512.New384, + jwa.HS512(): sha512.New, + } + + for alg, h := range algs { + hmacSignFuncs[alg] = makeHMACSignFunc(h) + } +} + +// HMACSigner uses crypto/hmac to sign the payloads. +// This is for legacy support only. +type HMACSigner struct { + alg jwa.SignatureAlgorithm + sign hmacSignFunc +} + +type HMACVerifier struct { + signer Signer +} + +type hmacSignFunc func(payload []byte, key []byte) ([]byte, error) + +var hmacSignFuncs = make(map[jwa.SignatureAlgorithm]hmacSignFunc) + +func NewHMACSigner(alg jwa.SignatureAlgorithm) Signer { + return &HMACSigner{ + alg: alg, + sign: hmacSignFuncs[alg], // we know this will succeed + } +} + +func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc { + return func(payload []byte, key []byte) ([]byte, error) { + h := hmac.New(hfunc, key) + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload using hmac: %w`, err) + } + return h.Sum(nil), nil + } +} + +func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm { + return s.alg +} + +func (s HMACSigner) Sign(payload []byte, key any) ([]byte, error) { + var hmackey []byte + if err := keyconv.ByteSliceKey(&hmackey, key); err != nil { + return nil, fmt.Errorf(`invalid key type %T. []byte is required: %w`, key, err) + } + + if len(hmackey) == 0 { + return nil, fmt.Errorf(`missing key while signing payload`) + } + + return s.sign(payload, hmackey) +} + +func NewHMACVerifier(alg jwa.SignatureAlgorithm) Verifier { + s := NewHMACSigner(alg) + return &HMACVerifier{signer: s} +} + +func (v HMACVerifier) Verify(payload, signature []byte, key any) (err error) { + expected, err := v.signer.Sign(payload, key) + if err != nil { + return fmt.Errorf(`failed to generated signature: %w`, err) + } + + if !hmac.Equal(signature, expected) { + return fmt.Errorf(`failed to match hmac signature`) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/legacy.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/legacy.go new file mode 100644 index 0000000000..84a2527428 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/legacy.go @@ -0,0 +1,36 @@ +// Package legacy provides support for legacy implementation of JWS signing and verification. +// Types, functions, and variables in this package are exported only for legacy support, +// and should not be relied upon for new code. +// +// This package will be available until v3 is sunset, but it will be removed in v4 +package legacy + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// Signer generates the signature for a given payload. +// This is for legacy support only. +type Signer interface { + // Sign creates a signature for the given payload. + // The second argument is the key used for signing the payload, and is usually + // the private key type associated with the signature method. For example, + // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the + // `*"crypto/rsa".PrivateKey` type. + // Check the documentation for each signer for details + Sign([]byte, any) ([]byte, error) + + Algorithm() jwa.SignatureAlgorithm +} + +// This is for legacy support only. +type Verifier interface { + // Verify checks whether the payload and signature are valid for + // the given key. + // `key` is the key used for verifying the payload, and is usually + // the public key associated with the signature method. For example, + // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the + // `*"crypto/rsa".PublicKey` type. + // Check the documentation for each verifier for details + Verify(payload []byte, signature []byte, key any) error +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/rsa.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/rsa.go new file mode 100644 index 0000000000..aef110a5cf --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/legacy/rsa.go @@ -0,0 +1,145 @@ +package legacy + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/keyconv" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/internal/keytype" +) + +var rsaSigners = make(map[jwa.SignatureAlgorithm]*rsaSigner) +var rsaVerifiers = make(map[jwa.SignatureAlgorithm]*rsaVerifier) + +func init() { + data := map[jwa.SignatureAlgorithm]struct { + Hash crypto.Hash + PSS bool + }{ + jwa.RS256(): { + Hash: crypto.SHA256, + }, + jwa.RS384(): { + Hash: crypto.SHA384, + }, + jwa.RS512(): { + Hash: crypto.SHA512, + }, + jwa.PS256(): { + Hash: crypto.SHA256, + PSS: true, + }, + jwa.PS384(): { + Hash: crypto.SHA384, + PSS: true, + }, + jwa.PS512(): { + Hash: crypto.SHA512, + PSS: true, + }, + } + + for alg, item := range data { + rsaSigners[alg] = &rsaSigner{ + alg: alg, + hash: item.Hash, + pss: item.PSS, + } + rsaVerifiers[alg] = &rsaVerifier{ + alg: alg, + hash: item.Hash, + pss: item.PSS, + } + } +} + +type rsaSigner struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash + pss bool +} + +func NewRSASigner(alg jwa.SignatureAlgorithm) Signer { + return rsaSigners[alg] +} + +func (rs *rsaSigner) Algorithm() jwa.SignatureAlgorithm { + return rs.alg +} + +func (rs *rsaSigner) Sign(payload []byte, key any) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`missing private key while signing payload`) + } + + signer, ok := key.(crypto.Signer) + if ok { + if !keytype.IsValidRSAKey(key) { + return nil, fmt.Errorf(`cannot use key of type %T to generate RSA based signatures`, key) + } + } else { + var privkey rsa.PrivateKey + if err := keyconv.RSAPrivateKey(&privkey, key); err != nil { + return nil, fmt.Errorf(`failed to retrieve rsa.PrivateKey out of %T: %w`, key, err) + } + signer = &privkey + } + + h := rs.hash.New() + if _, err := h.Write(payload); err != nil { + return nil, fmt.Errorf(`failed to write payload to hash: %w`, err) + } + if rs.pss { + return signer.Sign(rand.Reader, h.Sum(nil), &rsa.PSSOptions{ + Hash: rs.hash, + SaltLength: rsa.PSSSaltLengthEqualsHash, + }) + } + return signer.Sign(rand.Reader, h.Sum(nil), rs.hash) +} + +type rsaVerifier struct { + alg jwa.SignatureAlgorithm + hash crypto.Hash + pss bool +} + +func NewRSAVerifier(alg jwa.SignatureAlgorithm) Verifier { + return rsaVerifiers[alg] +} + +func (rv *rsaVerifier) Verify(payload, signature []byte, key any) error { + if key == nil { + return fmt.Errorf(`missing public key while verifying payload`) + } + + var pubkey rsa.PublicKey + if cs, ok := key.(crypto.Signer); ok { + cpub := cs.Public() + switch cpub := cpub.(type) { + case rsa.PublicKey: + pubkey = cpub + case *rsa.PublicKey: + pubkey = *cpub + default: + return fmt.Errorf(`failed to retrieve rsa.PublicKey out of crypto.Signer %T`, key) + } + } else { + if err := keyconv.RSAPublicKey(&pubkey, key); err != nil { + return fmt.Errorf(`failed to retrieve rsa.PublicKey out of %T: %w`, key, err) + } + } + + h := rv.hash.New() + if _, err := h.Write(payload); err != nil { + return fmt.Errorf(`failed to write payload to hash: %w`, err) + } + + if rv.pss { + return rsa.VerifyPSS(&pubkey, rv.hash, h.Sum(nil), signature, nil) + } + return rsa.VerifyPKCS1v15(&pubkey, rv.hash, h.Sum(nil), signature) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/message.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/message.go new file mode 100644 index 0000000000..e113d1438c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/message.go @@ -0,0 +1,550 @@ +package jws + +import ( + "bytes" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +func NewSignature() *Signature { + return &Signature{} +} + +func (s *Signature) DecodeCtx() DecodeCtx { + return s.dc +} + +func (s *Signature) SetDecodeCtx(dc DecodeCtx) { + s.dc = dc +} + +func (s Signature) PublicHeaders() Headers { + return s.headers +} + +func (s *Signature) SetPublicHeaders(v Headers) *Signature { + s.headers = v + return s +} + +func (s Signature) ProtectedHeaders() Headers { + return s.protected +} + +func (s *Signature) SetProtectedHeaders(v Headers) *Signature { + s.protected = v + return s +} + +func (s Signature) Signature() []byte { + return s.signature +} + +func (s *Signature) SetSignature(v []byte) *Signature { + s.signature = v + return s +} + +type signatureUnmarshalProbe struct { + Header Headers `json:"header,omitempty"` + Protected *string `json:"protected,omitempty"` + Signature *string `json:"signature,omitempty"` +} + +func (s *Signature) UnmarshalJSON(data []byte) error { + var sup signatureUnmarshalProbe + sup.Header = NewHeaders() + if err := json.Unmarshal(data, &sup); err != nil { + return fmt.Errorf(`failed to unmarshal signature into temporary struct: %w`, err) + } + + s.headers = sup.Header + if buf := sup.Protected; buf != nil { + src := []byte(*buf) + if !bytes.HasPrefix(src, []byte{tokens.OpenCurlyBracket}) { + decoded, err := base64.Decode(src) + if err != nil { + return fmt.Errorf(`failed to base64 decode protected headers: %w`, err) + } + src = decoded + } + + prt := NewHeaders() + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(s.DecodeCtx()) + if err := json.Unmarshal(src, prt); err != nil { + return fmt.Errorf(`failed to unmarshal protected headers: %w`, err) + } + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(nil) + s.protected = prt + } + + if sup.Signature != nil { + decoded, err := base64.DecodeString(*sup.Signature) + if err != nil { + return fmt.Errorf(`failed to base decode signature: %w`, err) + } + s.signature = decoded + } + return nil +} + +// Sign populates the signature field, with a signature generated by +// given the signer object and payload. +// +// The first return value is the raw signature in binary format. +// The second return value s the full three-segment signature +// (e.g. "eyXXXX.XXXXX.XXXX") +// +// This method is deprecated, and will be remove in a future release. +// Signature objects in the future will only be used as containers, +// and signing will be done using the `jws.Sign` function, or alternatively +// you could use jwsbb package to craft the signature manually. +func (s *Signature) Sign(payload []byte, signer Signer, key any) ([]byte, []byte, error) { + return s.sign2(payload, signer, key) +} + +func (s *Signature) sign2(payload []byte, signer interface{ Algorithm() jwa.SignatureAlgorithm }, key any) ([]byte, []byte, error) { + // Create a signatureBuilder to use the shared signing logic + sb := signatureBuilderPool.Get() + defer signatureBuilderPool.Put(sb) + + sb.alg = signer.Algorithm() + sb.key = key + sb.protected = s.protected + sb.public = s.headers + + // Set up the appropriate signer interface + switch typedSigner := signer.(type) { + case Signer2: + sb.signer2 = typedSigner + case Signer: + sb.signer = typedSigner + default: + return nil, nil, fmt.Errorf(`invalid signer type: %T`, signer) + } + + // Create a minimal sign context + sc := signContextPool.Get() + defer signContextPool.Put(sc) + + sc.detached = s.detached + + encoder := s.encoder + if encoder == nil { + encoder = base64.DefaultEncoder() + } + sc.encoder = encoder + + // Build the signature using signatureBuilder + sig, err := sb.Build(sc, payload) + if err != nil { + return nil, nil, fmt.Errorf(`failed to build signature: %w`, err) + } + + // Copy the signature result back to this signature instance + s.signature = sig.signature + s.protected = sig.protected + s.headers = sig.headers + + // Build the complete JWS token for the return value + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + // Marshal the merged headers for the final output + hdrs, err := mergeHeaders(s.headers, s.protected) + if err != nil { + return nil, nil, fmt.Errorf(`failed to merge headers: %w`, err) + } + + hdrbuf, err := json.Marshal(hdrs) + if err != nil { + return nil, nil, fmt.Errorf(`failed to marshal headers: %w`, err) + } + + buf.WriteString(encoder.EncodeToString(hdrbuf)) + buf.WriteByte(tokens.Period) + + var plen int + b64 := getB64Value(hdrs) + if b64 { + encoded := encoder.EncodeToString(payload) + plen = len(encoded) + buf.WriteString(encoded) + } else { + if !s.detached { + if bytes.Contains(payload, []byte{tokens.Period}) { + return nil, nil, fmt.Errorf(`payload must not contain a "."`) + } + } + plen = len(payload) + buf.Write(payload) + } + + // Handle detached payload + if s.detached { + buf.Truncate(buf.Len() - plen) + } + + buf.WriteByte(tokens.Period) + buf.WriteString(encoder.EncodeToString(s.signature)) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + + return s.signature, ret, nil +} + +func NewMessage() *Message { + return &Message{} +} + +// Clears the internal raw buffer that was accumulated during +// the verify phase +func (m *Message) clearRaw() { + for _, sig := range m.signatures { + if protected := sig.protected; protected != nil { + if cr, ok := protected.(*stdHeaders); ok { + cr.raw = nil + } + } + } +} + +func (m *Message) SetDecodeCtx(dc DecodeCtx) { + m.dc = dc +} + +func (m *Message) DecodeCtx() DecodeCtx { + return m.dc +} + +// Payload returns the decoded payload +func (m Message) Payload() []byte { + return m.payload +} + +func (m *Message) SetPayload(v []byte) *Message { + m.payload = v + return m +} + +func (m Message) Signatures() []*Signature { + return m.signatures +} + +func (m *Message) AppendSignature(v *Signature) *Message { + m.signatures = append(m.signatures, v) + return m +} + +func (m *Message) ClearSignatures() *Message { + m.signatures = nil + return m +} + +// LookupSignature looks up a particular signature entry using +// the `kid` value +func (m Message) LookupSignature(kid string) []*Signature { + var sigs []*Signature + for _, sig := range m.signatures { + if hdr := sig.PublicHeaders(); hdr != nil { + hdrKeyID, ok := hdr.KeyID() + if ok && hdrKeyID == kid { + sigs = append(sigs, sig) + continue + } + } + + if hdr := sig.ProtectedHeaders(); hdr != nil { + hdrKeyID, ok := hdr.KeyID() + if ok && hdrKeyID == kid { + sigs = append(sigs, sig) + continue + } + } + } + return sigs +} + +// This struct is used to first probe for the structure of the +// incoming JSON object. We then decide how to parse it +// from the fields that are populated. +type messageUnmarshalProbe struct { + Payload *string `json:"payload"` + Signatures []json.RawMessage `json:"signatures,omitempty"` + Header Headers `json:"header,omitempty"` + Protected *string `json:"protected,omitempty"` + Signature *string `json:"signature,omitempty"` +} + +func (m *Message) UnmarshalJSON(buf []byte) error { + m.payload = nil + m.signatures = nil + m.b64 = true + + var mup messageUnmarshalProbe + mup.Header = NewHeaders() + if err := json.Unmarshal(buf, &mup); err != nil { + return fmt.Errorf(`failed to unmarshal into temporary structure: %w`, err) + } + + b64 := true + if mup.Signature == nil { // flattened signature is NOT present + if len(mup.Signatures) == 0 { + return fmt.Errorf(`required field "signatures" not present`) + } + + m.signatures = make([]*Signature, 0, len(mup.Signatures)) + for i, rawsig := range mup.Signatures { + var sig Signature + sig.SetDecodeCtx(m.DecodeCtx()) + if err := json.Unmarshal(rawsig, &sig); err != nil { + return fmt.Errorf(`failed to unmarshal signature #%d: %w`, i+1, err) + } + sig.SetDecodeCtx(nil) + + if sig.protected == nil { + // Instead of barfing on a nil protected header, use an empty header + sig.protected = NewHeaders() + } + + if i == 0 { + if !getB64Value(sig.protected) { + b64 = false + } + } else { + if b64 != getB64Value(sig.protected) { + return fmt.Errorf(`b64 value must be the same for all signatures`) + } + } + + m.signatures = append(m.signatures, &sig) + } + } else { // .signature is present, it's a flattened structure + if len(mup.Signatures) != 0 { + return fmt.Errorf(`invalid format ("signatures" and "signature" keys cannot both be present)`) + } + + var sig Signature + sig.headers = mup.Header + if src := mup.Protected; src != nil { + decoded, err := base64.DecodeString(*src) + if err != nil { + return fmt.Errorf(`failed to base64 decode flattened protected headers: %w`, err) + } + prt := NewHeaders() + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(m.DecodeCtx()) + if err := json.Unmarshal(decoded, prt); err != nil { + return fmt.Errorf(`failed to unmarshal flattened protected headers: %w`, err) + } + //nolint:forcetypeassert + prt.(*stdHeaders).SetDecodeCtx(nil) + sig.protected = prt + } + + if sig.protected == nil { + // Instead of barfing on a nil protected header, use an empty header + sig.protected = NewHeaders() + } + + decoded, err := base64.DecodeString(*mup.Signature) + if err != nil { + return fmt.Errorf(`failed to base64 decode flattened signature: %w`, err) + } + sig.signature = decoded + + m.signatures = []*Signature{&sig} + b64 = getB64Value(sig.protected) + } + + if mup.Payload != nil { + if !b64 { // NOT base64 encoded + m.payload = []byte(*mup.Payload) + } else { + decoded, err := base64.DecodeString(*mup.Payload) + if err != nil { + return fmt.Errorf(`failed to base64 decode payload: %w`, err) + } + m.payload = decoded + } + } + m.b64 = b64 + return nil +} + +func (m Message) MarshalJSON() ([]byte, error) { + if len(m.signatures) == 1 { + return m.marshalFlattened() + } + return m.marshalFull() +} + +func (m Message) marshalFlattened() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + sig := m.signatures[0] + + buf.WriteRune(tokens.OpenCurlyBracket) + var wrote bool + + if hdr := sig.headers; hdr != nil { + hdrjs, err := json.Marshal(hdr) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "header" (flattened format): %w`, err) + } + buf.WriteString(`"header":`) + buf.Write(hdrjs) + wrote = true + } + + if wrote { + buf.WriteRune(tokens.Comma) + } + buf.WriteString(`"payload":"`) + buf.WriteString(base64.EncodeToString(m.payload)) + buf.WriteRune('"') + + if protected := sig.protected; protected != nil { + protectedbuf, err := json.Marshal(protected) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "protected" (flattened format): %w`, err) + } + buf.WriteString(`,"protected":"`) + buf.WriteString(base64.EncodeToString(protectedbuf)) + buf.WriteRune('"') + } + + buf.WriteString(`,"signature":"`) + buf.WriteString(base64.EncodeToString(sig.signature)) + buf.WriteRune('"') + buf.WriteRune(tokens.CloseCurlyBracket) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +func (m Message) marshalFull() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(`{"payload":"`) + buf.WriteString(base64.EncodeToString(m.payload)) + buf.WriteString(`","signatures":[`) + for i, sig := range m.signatures { + if i > 0 { + buf.WriteRune(tokens.Comma) + } + + buf.WriteRune(tokens.OpenCurlyBracket) + var wrote bool + if hdr := sig.headers; hdr != nil { + hdrbuf, err := json.Marshal(hdr) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "header" for signature #%d: %w`, i+1, err) + } + buf.WriteString(`"header":`) + buf.Write(hdrbuf) + wrote = true + } + + if protected := sig.protected; protected != nil { + protectedbuf, err := json.Marshal(protected) + if err != nil { + return nil, fmt.Errorf(`failed to marshal "protected" for signature #%d: %w`, i+1, err) + } + if wrote { + buf.WriteRune(tokens.Comma) + } + buf.WriteString(`"protected":"`) + buf.WriteString(base64.EncodeToString(protectedbuf)) + buf.WriteRune('"') + wrote = true + } + + if len(sig.signature) > 0 { + // If InsecureNoSignature is enabled, signature may not exist + if wrote { + buf.WriteRune(tokens.Comma) + } + buf.WriteString(`"signature":"`) + buf.WriteString(base64.EncodeToString(sig.signature)) + buf.WriteString(`"`) + } + buf.WriteString(`}`) + } + buf.WriteString(`]}`) + + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} + +// Compact generates a JWS message in compact serialization format from +// `*jws.Message` object. The object contain exactly one signature, or +// an error is returned. +// +// If using a detached payload, the payload must already be stored in +// the `*jws.Message` object, and the `jws.WithDetached()` option +// must be passed to the function. +func Compact(msg *Message, options ...CompactOption) ([]byte, error) { + if l := len(msg.signatures); l != 1 { + return nil, fmt.Errorf(`jws.Compact: cannot serialize message with %d signatures (must be one)`, l) + } + + var detached bool + var encoder Base64Encoder = base64.DefaultEncoder() + for _, option := range options { + switch option.Ident() { + case identDetached{}: + if err := option.Value(&detached); err != nil { + return nil, fmt.Errorf(`jws.Compact: failed to retrieve detached option value: %w`, err) + } + case identBase64Encoder{}: + if err := option.Value(&encoder); err != nil { + return nil, fmt.Errorf(`jws.Compact: failed to retrieve base64 encoder option value: %w`, err) + } + } + } + + s := msg.signatures[0] + // XXX check if this is correct + hdrs := s.ProtectedHeaders() + + hdrbuf, err := json.Marshal(hdrs) + if err != nil { + return nil, fmt.Errorf(`jws.Compress: failed to marshal headers: %w`, err) + } + + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + + buf.WriteString(encoder.EncodeToString(hdrbuf)) + buf.WriteByte(tokens.Period) + + if !detached { + if getB64Value(hdrs) { + encoded := encoder.EncodeToString(msg.payload) + buf.WriteString(encoded) + } else { + if bytes.Contains(msg.payload, []byte{tokens.Period}) { + return nil, fmt.Errorf(`jws.Compress: payload must not contain a "."`) + } + buf.Write(msg.payload) + } + } + + buf.WriteByte(tokens.Period) + buf.WriteString(encoder.EncodeToString(s.signature)) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.go new file mode 100644 index 0000000000..729e561936 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.go @@ -0,0 +1,259 @@ +package jws + +import ( + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/option/v2" +) + +type identInsecureNoSignature struct{} + +// WithJSON specifies that the result of `jws.Sign()` is serialized in +// JSON format. +// +// If you pass multiple keys to `jws.Sign()`, it will fail unless +// you also pass this option. +func WithJSON(options ...WithJSONSuboption) SignVerifyParseOption { + var pretty bool + for _, option := range options { + switch option.Ident() { + case identPretty{}: + if err := option.Value(&pretty); err != nil { + panic(`jws.WithJSON() option must be of type bool`) + } + } + } + + format := fmtJSON + if pretty { + format = fmtJSONPretty + } + return &signVerifyParseOption{option.New(identSerialization{}, format)} +} + +type withKey struct { + alg jwa.KeyAlgorithm + key any + protected Headers + public Headers +} + +// This exists as an escape hatch to modify the header values after the fact +func (w *withKey) Protected(v Headers) Headers { + if w.protected == nil && v != nil { + w.protected = v + } + return w.protected +} + +// WithKey is used to pass a static algorithm/key pair to either `jws.Sign()` or `jws.Verify()`. +// +// The `alg` parameter is the identifier for the signature algorithm that should be used. +// It is of type `jwa.KeyAlgorithm` but in reality you can only pass `jwa.SignatureAlgorithm` +// types. It is this way so that the value in `(jwk.Key).Algorithm()` can be directly +// passed to the option. If you specify other algorithm types such as `jwa.KeyEncryptionAlgorithm`, +// then you will get an error when `jws.Sign()` or `jws.Verify()` is executed. +// +// The `alg` parameter cannot be "none" (jwa.NoSignature) for security reasons. +// You will have to use a separate, more explicit option to allow the use of "none" +// algorithm (WithInsecureNoSignature). +// +// The algorithm specified in the `alg` parameter MUST be able to support +// the type of key you provided, otherwise an error is returned. +// +// Any of the following is accepted for the `key` parameter: +// * A "raw" key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) +// * A crypto.Signer +// * A jwk.Key +// +// Note that due to technical reasons, this library is NOT able to differentiate +// between a valid/invalid key for given algorithm if the key implements crypto.Signer +// and the key is from an external library. For example, while we can tell that it is +// invalid to use `jwk.WithKey(jwa.RSA256, ecdsaPrivateKey)` because the key is +// presumably from `crypto/ecdsa` or this library, if you use a KMS wrapper +// that implements crypto.Signer that is outside of the go standard library or this +// library, we will not be able to properly catch the misuse of such keys -- +// the output will happily generate an ECDSA signature even in the presence of +// `jwa.RSA256` +// +// A `crypto.Signer` is used when the private part of a key is +// kept in an inaccessible location, such as hardware. +// `crypto.Signer` is currently supported for RSA, ECDSA, and EdDSA +// family of algorithms. You may consider using `github.com/jwx-go/crypto-signer` +// if you would like to use keys stored in GCP/AWS KMS services. +// +// If the key is a jwk.Key and the key contains a key ID (`kid` field), +// then it is added to the protected header generated by the signature. +// +// `jws.WithKey()` can further accept suboptions to change signing behavior +// when used with `jws.Sign()`. `jws.WithProtected()` and `jws.WithPublic()` +// can be passed to specify JWS headers that should be used whe signing. +// +// If the protected headers contain "b64" field, then the boolean value for the field +// is respected when serializing. That is, if you specify a header with +// `{"b64": false}`, then the payload is not base64 encoded. +// +// These suboptions are ignored when the `jws.WithKey()` option is used with `jws.Verify()`. +func WithKey(alg jwa.KeyAlgorithm, key any, options ...WithKeySuboption) SignVerifyOption { + // Implementation note: this option is shared between Sign() and + // Verify(). As such we don't create a KeyProvider here because + // if used in Sign() we would be doing something else. + var protected, public Headers + for _, option := range options { + switch option.Ident() { + case identProtectedHeaders{}: + if err := option.Value(&protected); err != nil { + panic(`jws.WithKey() option must be of type Headers`) + } + case identPublicHeaders{}: + if err := option.Value(&public); err != nil { + panic(`jws.WithKey() option must be of type Headers`) + } + } + } + + return &signVerifyOption{ + option.New(identKey{}, &withKey{ + alg: alg, + key: key, + protected: protected, + public: public, + }), + } +} + +// WithKeySet specifies a JWKS (jwk.Set) to use for verification. +// +// Because a JWKS can contain multiple keys and this library cannot tell +// which one of the keys should be used for verification, we by default +// require that both `alg` and `kid` fields in the JWS _and_ the +// key match before a key is considered to be used. +// +// There are ways to override this behavior, but they must be explicitly +// specified by the caller. +// +// To work with keys/JWS messages not having a `kid` field, you may specify +// the suboption `WithKeySetRequired` via `jws.WithKey(key, jws.WithRequireKid(false))`. +// This will allow the library to proceed without having to match the `kid` field. +// +// However, it will still check if the `alg` fields in the JWS message and the key(s) +// match. If you must work with JWS messages that do not have an `alg` field, +// you will need to use `jws.WithKeySet(key, jws.WithInferAlgorithm(true))`. +// +// See the documentation for `WithInferAlgorithm()` for more details. +func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) VerifyOption { + requireKid := true + var useDefault, inferAlgorithm, multipleKeysPerKeyID bool + for _, option := range options { + switch option.Ident() { + case identRequireKid{}: + if err := option.Value(&requireKid); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + case identUseDefault{}: + if err := option.Value(&useDefault); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + case identMultipleKeysPerKeyID{}: + if err := option.Value(&multipleKeysPerKeyID); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + case identInferAlgorithmFromKey{}: + if err := option.Value(&inferAlgorithm); err != nil { + panic(`jws.WithKeySet() option must be of type bool`) + } + } + } + + return WithKeyProvider(&keySetProvider{ + set: set, + requireKid: requireKid, + useDefault: useDefault, + multipleKeysPerKeyID: multipleKeysPerKeyID, + inferAlgorithm: inferAlgorithm, + }) +} + +// WithVerifyAuto enables automatic verification of the signature using the JWKS specified in +// the `jku` header. Note that by default this option will _reject_ any jku +// provided by the JWS message. Read on for details. +// +// The JWKS is retrieved by the `jwk.Fetcher` specified in the first argument. +// If the fetcher object is nil, the default fetcher, which is the `jwk.Fetch()` +// function (wrapped in the `jwk.FetchFunc` type) is used. +// +// The remaining arguments are passed to the `(jwk.Fetcher).Fetch` method +// when the JWKS is retrieved. +// +// jws.WithVerifyAuto(nil) // uses jwk.Fetch +// jws.WithVerifyAuto(jwk.NewCachedFetcher(...)) // uses cached fetcher +// jws.WithVerifyAuto(myFetcher) // use your custom fetcher +// +// By default a whitelist that disallows all URLs is added to the options +// passed to the fetcher. You must explicitly specify a whitelist that allows +// the URLs you trust. This default behavior is provided because by design +// of the JWS specification it is the/ caller's responsibility to verify if +// the URL specified in the `jku` header can be trusted -- thus by default +// we trust nothing. +// +// Users are free to specify an open whitelist if they so choose, but this must +// be explicitly done: +// +// jws.WithVerifyAuto(nil, jwk.WithFetchWhitelist(jwk.InsecureWhitelist())) +// +// You can also use `jwk.CachedFetcher` to use cached JWKS objects, but do note +// that this object is not really designed to accommodate a large set of +// arbitrary URLs. Use `jwk.CachedFetcher` as the first argument if you only +// have a small set of URLs that you trust. For anything more complex, you should +// implement your own `jwk.Fetcher` object. +func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) VerifyOption { + // the option MUST start with a "disallow no whitelist" to force + // users provide a whitelist + options = append(append([]jwk.FetchOption(nil), jwk.WithFetchWhitelist(allowNoneWhitelist)), options...) + + return WithKeyProvider(jkuProvider{ + fetcher: f, + options: options, + }) +} + +type withInsecureNoSignature struct { + protected Headers +} + +// This exists as an escape hatch to modify the header values after the fact +func (w *withInsecureNoSignature) Protected(v Headers) Headers { + if w.protected == nil && v != nil { + w.protected = v + } + return w.protected +} + +// WithInsecureNoSignature creates an option that allows the user to use the +// "none" signature algorithm. +// +// Please note that this is insecure, and should never be used in production +// (this is exactly why specifying "none"/jwa.NoSignature to `jws.WithKey()` +// results in an error when `jws.Sign()` is called -- we do not allow using +// "none" by accident) +// +// TODO: create specific suboption set for this option +func WithInsecureNoSignature(options ...WithKeySuboption) SignOption { + var protected Headers + for _, option := range options { + switch option.Ident() { + case identProtectedHeaders{}: + if err := option.Value(&protected); err != nil { + panic(`jws.WithInsecureNoSignature() option must be of type Headers`) + } + } + } + + return &signOption{ + option.New(identInsecureNoSignature{}, + &withInsecureNoSignature{ + protected: protected, + }, + ), + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.yaml new file mode 100644 index 0000000000..303ab3a32e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/options.yaml @@ -0,0 +1,234 @@ +package_name: jws +output: jws/options_gen.go +interfaces: + - name: CompactOption + comment: | + CompactOption describes options that can be passed to `jws.Compact` + - name: VerifyOption + comment: | + VerifyOption describes options that can be passed to `jws.Verify` + methods: + - verifyOption + - parseOption + - name: SignOption + comment: | + SignOption describes options that can be passed to `jws.Sign` + - name: SignVerifyOption + methods: + - signOption + - verifyOption + - parseOption + comment: | + SignVerifyOption describes options that can be passed to either `jws.Verify` or `jws.Sign` + - name: SignVerifyCompactOption + methods: + - signOption + - verifyOption + - compactOption + - parseOption + comment: | + SignVerifyCompactOption describes options that can be passed to either `jws.Verify`, + `jws.Sign`, or `jws.Compact` + - name: WithJSONSuboption + concrete_type: withJSONSuboption + comment: | + JSONSuboption describes suboptions that can be passed to the `jws.WithJSON()` option. + - name: WithKeySuboption + comment: | + WithKeySuboption describes option types that can be passed to the `jws.WithKey()` + option. + - name: WithKeySetSuboption + comment: | + WithKeySetSuboption is a suboption passed to the `jws.WithKeySet()` option + - name: ParseOption + methods: + - readFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` + - name: SignVerifyParseOption + methods: + - signOption + - verifyOption + - parseOption + - readFileOption + - name: GlobalOption + comment: | + GlobalOption can be passed to `jws.Settings()` to set global options for the JWS package. +options: + - ident: Key + skip_option: true + - ident: Serialization + skip_option: true + - ident: Serialization + option_name: WithCompact + interface: SignVerifyParseOption + constant_value: fmtCompact + comment: | + WithCompact specifies that the result of `jws.Sign()` is serialized in + compact format. + + By default `jws.Sign()` will opt to use compact format, so you usually + do not need to specify this option other than to be explicit about it + - ident: Detached + interface: CompactOption + argument_type: bool + comment: | + WithDetached specifies that the `jws.Message` should be serialized in + JWS compact serialization with detached payload. The resulting octet + sequence will not contain the payload section. + + - ident: DetachedPayload + interface: SignVerifyOption + argument_type: '[]byte' + comment: | + WithDetachedPayload can be used to both sign or verify a JWS message with a + detached payload. + Note that this option does NOT populate the `b64` header, which is sometimes + required by other JWS implementations. + + + When this option is used for `jws.Sign()`, the first parameter (normally the payload) + must be set to `nil`. + + If you have to verify using this option, you should know exactly how and why this works. + - ident: Base64Encoder + interface: SignVerifyCompactOption + argument_type: Base64Encoder + comment: | + WithBase64Encoder specifies the base64 encoder to be used while signing or + verifying the JWS message. By default, the raw URL base64 encoding (no padding) + is used. + - ident: Message + interface: VerifyOption + argument_type: '*Message' + comment: | + WithMessage can be passed to Verify() to obtain the jws.Message upon + a successful verification. + - ident: KeyUsed + interface: VerifyOption + argument_type: 'any' + comment: | + WithKeyUsed allows you to specify the `jws.Verify()` function to + return the key used for verification. This may be useful when + you specify multiple key sources or if you pass a `jwk.Set` + and you want to know which key was successful at verifying the + signature. + + `v` must be a pointer to an empty `any`. Do not use + `jwk.Key` here unless you are 100% sure that all keys that you + have provided are instances of `jwk.Key` (remember that the + jwx API allows users to specify a raw key such as *rsa.PublicKey) + - ident: ValidateKey + interface: SignVerifyOption + argument_type: bool + comment: | + WithValidateKey specifies whether the key used for signing or verification + should be validated before using. Note that this means calling + `key.Validate()` on the key, which in turn means that your key + must be a `jwk.Key` instance, or a key that can be converted to + a `jwk.Key` by calling `jwk.Import()`. This means that your + custom hardware-backed keys will probably not work. + + You can directly call `key.Validate()` yourself if you need to + mix keys that cannot be converted to `jwk.Key`. + + Please also note that use of this option will also result in + one extra conversion of raw keys to a `jwk.Key` instance. If you + care about shaving off as much as possible, consider using a + pre-validated key instead of using this option to validate + the key on-demand each time. + + By default, the key is not validated. + - ident: InferAlgorithmFromKey + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithInferAlgorithmFromKey specifies whether the JWS signing algorithm name + should be inferred by looking at the provided key, in case the JWS + message or the key does not have a proper `alg` header. + + When this option is set to true, a list of algorithm(s) that is compatible + with the key type will be enumerated, and _ALL_ of them will be tried + against the key/message pair. If any of them succeeds, the verification + will be considered successful. + + Compared to providing explicit `alg` from the key this is slower, and + verification may fail to verify if somehow our heuristics are wrong + or outdated. + + Also, automatic detection of signature verification methods are always + more vulnerable for potential attack vectors. + + It is highly recommended that you fix your key to contain a proper `alg` + header field instead of resorting to using this option, but sometimes + it just needs to happen. + - ident: UseDefault + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithUseDefault specifies that if and only if a jwk.Key contains + exactly one jwk.Key, that key should be used. + - ident: RequireKid + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithRequiredKid specifies whether the keys in the jwk.Set should + only be matched if the target JWS message's Key ID and the Key ID + in the given key matches. + - ident: MultipleKeysPerKeyID + interface: WithKeySetSuboption + argument_type: bool + comment: | + WithMultipleKeysPerKeyID specifies if we should expect multiple keys + to match against a key ID. By default it is assumed that key IDs are + unique, i.e. for a given key ID, the key set only contains a single + key that has the matching ID. When this option is set to true, + multiple keys that match the same key ID in the set can be tried. + - ident: Pretty + interface: WithJSONSuboption + argument_type: bool + comment: | + WithPretty specifies whether the JSON output should be formatted and + indented + - ident: KeyProvider + interface: VerifyOption + argument_type: KeyProvider + - ident: Context + interface: VerifyOption + argument_type: context.Context + - ident: ProtectedHeaders + interface: WithKeySuboption + argument_type: Headers + comment: | + WithProtected is used with `jws.WithKey()` option when used with `jws.Sign()` + to specify a protected header to be attached to the JWS signature. + + It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` + - ident: PublicHeaders + interface: WithKeySuboption + argument_type: Headers + comment: | + WithPublic is used with `jws.WithKey()` option when used with `jws.Sign()` + to specify a public header to be attached to the JWS signature. + + It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` + + `jws.Sign()` will result in an error if `jws.WithPublic()` is used + and the serialization format is compact serialization. + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: LegacySigners + interface: GlobalOption + constant_value: true + comment: | + WithLegacySigners specifies whether the JWS package should use legacy + signers for signing JWS messages. + + Usually there's no need to use this option, as the new signers and + verifiers are loaded by default. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/options_gen.go new file mode 100644 index 0000000000..b97cf7e8dd --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/options_gen.go @@ -0,0 +1,449 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jws + +import ( + "context" + "io/fs" + + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// CompactOption describes options that can be passed to `jws.Compact` +type CompactOption interface { + Option + compactOption() +} + +type compactOption struct { + Option +} + +func (*compactOption) compactOption() {} + +// GlobalOption can be passed to `jws.Settings()` to set global options for the JWS package. +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jwe.Parse` +type ParseOption interface { + Option + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// SignOption describes options that can be passed to `jws.Sign` +type SignOption interface { + Option + signOption() +} + +type signOption struct { + Option +} + +func (*signOption) signOption() {} + +// SignVerifyCompactOption describes options that can be passed to either `jws.Verify`, +// `jws.Sign`, or `jws.Compact` +type SignVerifyCompactOption interface { + Option + signOption() + verifyOption() + compactOption() + parseOption() +} + +type signVerifyCompactOption struct { + Option +} + +func (*signVerifyCompactOption) signOption() {} + +func (*signVerifyCompactOption) verifyOption() {} + +func (*signVerifyCompactOption) compactOption() {} + +func (*signVerifyCompactOption) parseOption() {} + +// SignVerifyOption describes options that can be passed to either `jws.Verify` or `jws.Sign` +type SignVerifyOption interface { + Option + signOption() + verifyOption() + parseOption() +} + +type signVerifyOption struct { + Option +} + +func (*signVerifyOption) signOption() {} + +func (*signVerifyOption) verifyOption() {} + +func (*signVerifyOption) parseOption() {} + +type SignVerifyParseOption interface { + Option + signOption() + verifyOption() + parseOption() + readFileOption() +} + +type signVerifyParseOption struct { + Option +} + +func (*signVerifyParseOption) signOption() {} + +func (*signVerifyParseOption) verifyOption() {} + +func (*signVerifyParseOption) parseOption() {} + +func (*signVerifyParseOption) readFileOption() {} + +// VerifyOption describes options that can be passed to `jws.Verify` +type VerifyOption interface { + Option + verifyOption() + parseOption() +} + +type verifyOption struct { + Option +} + +func (*verifyOption) verifyOption() {} + +func (*verifyOption) parseOption() {} + +// JSONSuboption describes suboptions that can be passed to the `jws.WithJSON()` option. +type WithJSONSuboption interface { + Option + withJSONSuboption() +} + +type withJSONSuboption struct { + Option +} + +func (*withJSONSuboption) withJSONSuboption() {} + +// WithKeySetSuboption is a suboption passed to the `jws.WithKeySet()` option +type WithKeySetSuboption interface { + Option + withKeySetSuboption() +} + +type withKeySetSuboption struct { + Option +} + +func (*withKeySetSuboption) withKeySetSuboption() {} + +// WithKeySuboption describes option types that can be passed to the `jws.WithKey()` +// option. +type WithKeySuboption interface { + Option + withKeySuboption() +} + +type withKeySuboption struct { + Option +} + +func (*withKeySuboption) withKeySuboption() {} + +type identBase64Encoder struct{} +type identContext struct{} +type identDetached struct{} +type identDetachedPayload struct{} +type identFS struct{} +type identInferAlgorithmFromKey struct{} +type identKey struct{} +type identKeyProvider struct{} +type identKeyUsed struct{} +type identLegacySigners struct{} +type identMessage struct{} +type identMultipleKeysPerKeyID struct{} +type identPretty struct{} +type identProtectedHeaders struct{} +type identPublicHeaders struct{} +type identRequireKid struct{} +type identSerialization struct{} +type identUseDefault struct{} +type identValidateKey struct{} + +func (identBase64Encoder) String() string { + return "WithBase64Encoder" +} + +func (identContext) String() string { + return "WithContext" +} + +func (identDetached) String() string { + return "WithDetached" +} + +func (identDetachedPayload) String() string { + return "WithDetachedPayload" +} + +func (identFS) String() string { + return "WithFS" +} + +func (identInferAlgorithmFromKey) String() string { + return "WithInferAlgorithmFromKey" +} + +func (identKey) String() string { + return "WithKey" +} + +func (identKeyProvider) String() string { + return "WithKeyProvider" +} + +func (identKeyUsed) String() string { + return "WithKeyUsed" +} + +func (identLegacySigners) String() string { + return "WithLegacySigners" +} + +func (identMessage) String() string { + return "WithMessage" +} + +func (identMultipleKeysPerKeyID) String() string { + return "WithMultipleKeysPerKeyID" +} + +func (identPretty) String() string { + return "WithPretty" +} + +func (identProtectedHeaders) String() string { + return "WithProtectedHeaders" +} + +func (identPublicHeaders) String() string { + return "WithPublicHeaders" +} + +func (identRequireKid) String() string { + return "WithRequireKid" +} + +func (identSerialization) String() string { + return "WithSerialization" +} + +func (identUseDefault) String() string { + return "WithUseDefault" +} + +func (identValidateKey) String() string { + return "WithValidateKey" +} + +// WithBase64Encoder specifies the base64 encoder to be used while signing or +// verifying the JWS message. By default, the raw URL base64 encoding (no padding) +// is used. +func WithBase64Encoder(v Base64Encoder) SignVerifyCompactOption { + return &signVerifyCompactOption{option.New(identBase64Encoder{}, v)} +} + +func WithContext(v context.Context) VerifyOption { + return &verifyOption{option.New(identContext{}, v)} +} + +// WithDetached specifies that the `jws.Message` should be serialized in +// JWS compact serialization with detached payload. The resulting octet +// sequence will not contain the payload section. +func WithDetached(v bool) CompactOption { + return &compactOption{option.New(identDetached{}, v)} +} + +// WithDetachedPayload can be used to both sign or verify a JWS message with a +// detached payload. +// Note that this option does NOT populate the `b64` header, which is sometimes +// required by other JWS implementations. +// +// When this option is used for `jws.Sign()`, the first parameter (normally the payload) +// must be set to `nil`. +// +// If you have to verify using this option, you should know exactly how and why this works. +func WithDetachedPayload(v []byte) SignVerifyOption { + return &signVerifyOption{option.New(identDetachedPayload{}, v)} +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +// WithInferAlgorithmFromKey specifies whether the JWS signing algorithm name +// should be inferred by looking at the provided key, in case the JWS +// message or the key does not have a proper `alg` header. +// +// When this option is set to true, a list of algorithm(s) that is compatible +// with the key type will be enumerated, and _ALL_ of them will be tried +// against the key/message pair. If any of them succeeds, the verification +// will be considered successful. +// +// Compared to providing explicit `alg` from the key this is slower, and +// verification may fail to verify if somehow our heuristics are wrong +// or outdated. +// +// Also, automatic detection of signature verification methods are always +// more vulnerable for potential attack vectors. +// +// It is highly recommended that you fix your key to contain a proper `alg` +// header field instead of resorting to using this option, but sometimes +// it just needs to happen. +func WithInferAlgorithmFromKey(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identInferAlgorithmFromKey{}, v)} +} + +func WithKeyProvider(v KeyProvider) VerifyOption { + return &verifyOption{option.New(identKeyProvider{}, v)} +} + +// WithKeyUsed allows you to specify the `jws.Verify()` function to +// return the key used for verification. This may be useful when +// you specify multiple key sources or if you pass a `jwk.Set` +// and you want to know which key was successful at verifying the +// signature. +// +// `v` must be a pointer to an empty `any`. Do not use +// `jwk.Key` here unless you are 100% sure that all keys that you +// have provided are instances of `jwk.Key` (remember that the +// jwx API allows users to specify a raw key such as *rsa.PublicKey) +func WithKeyUsed(v any) VerifyOption { + return &verifyOption{option.New(identKeyUsed{}, v)} +} + +// WithLegacySigners specifies whether the JWS package should use legacy +// signers for signing JWS messages. +// +// Usually there's no need to use this option, as the new signers and +// verifiers are loaded by default. +func WithLegacySigners() GlobalOption { + return &globalOption{option.New(identLegacySigners{}, true)} +} + +// WithMessage can be passed to Verify() to obtain the jws.Message upon +// a successful verification. +func WithMessage(v *Message) VerifyOption { + return &verifyOption{option.New(identMessage{}, v)} +} + +// WithMultipleKeysPerKeyID specifies if we should expect multiple keys +// to match against a key ID. By default it is assumed that key IDs are +// unique, i.e. for a given key ID, the key set only contains a single +// key that has the matching ID. When this option is set to true, +// multiple keys that match the same key ID in the set can be tried. +func WithMultipleKeysPerKeyID(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identMultipleKeysPerKeyID{}, v)} +} + +// WithPretty specifies whether the JSON output should be formatted and +// indented +func WithPretty(v bool) WithJSONSuboption { + return &withJSONSuboption{option.New(identPretty{}, v)} +} + +// WithProtected is used with `jws.WithKey()` option when used with `jws.Sign()` +// to specify a protected header to be attached to the JWS signature. +// +// It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` +func WithProtectedHeaders(v Headers) WithKeySuboption { + return &withKeySuboption{option.New(identProtectedHeaders{}, v)} +} + +// WithPublic is used with `jws.WithKey()` option when used with `jws.Sign()` +// to specify a public header to be attached to the JWS signature. +// +// It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()` +// +// `jws.Sign()` will result in an error if `jws.WithPublic()` is used +// and the serialization format is compact serialization. +func WithPublicHeaders(v Headers) WithKeySuboption { + return &withKeySuboption{option.New(identPublicHeaders{}, v)} +} + +// WithRequiredKid specifies whether the keys in the jwk.Set should +// only be matched if the target JWS message's Key ID and the Key ID +// in the given key matches. +func WithRequireKid(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identRequireKid{}, v)} +} + +// WithCompact specifies that the result of `jws.Sign()` is serialized in +// compact format. +// +// By default `jws.Sign()` will opt to use compact format, so you usually +// do not need to specify this option other than to be explicit about it +func WithCompact() SignVerifyParseOption { + return &signVerifyParseOption{option.New(identSerialization{}, fmtCompact)} +} + +// WithUseDefault specifies that if and only if a jwk.Key contains +// exactly one jwk.Key, that key should be used. +func WithUseDefault(v bool) WithKeySetSuboption { + return &withKeySetSuboption{option.New(identUseDefault{}, v)} +} + +// WithValidateKey specifies whether the key used for signing or verification +// should be validated before using. Note that this means calling +// `key.Validate()` on the key, which in turn means that your key +// must be a `jwk.Key` instance, or a key that can be converted to +// a `jwk.Key` by calling `jwk.Import()`. This means that your +// custom hardware-backed keys will probably not work. +// +// You can directly call `key.Validate()` yourself if you need to +// mix keys that cannot be converted to `jwk.Key`. +// +// Please also note that use of this option will also result in +// one extra conversion of raw keys to a `jwk.Key` instance. If you +// care about shaving off as much as possible, consider using a +// pre-validated key instead of using this option to validate +// the key on-demand each time. +// +// By default, the key is not validated. +func WithValidateKey(v bool) SignVerifyOption { + return &signVerifyOption{option.New(identValidateKey{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/sign_context.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/sign_context.go new file mode 100644 index 0000000000..49abe0abca --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/sign_context.go @@ -0,0 +1,141 @@ +package jws + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" +) + +type signContext struct { + format int + detached bool + validateKey bool + payload []byte + encoder Base64Encoder + none *signatureBuilder // special signature builder + sigbuilders []*signatureBuilder +} + +var signContextPool = pool.New[*signContext](allocSignContext, freeSignContext) + +func allocSignContext() *signContext { + return &signContext{ + format: fmtCompact, + sigbuilders: make([]*signatureBuilder, 0, 1), + encoder: base64.DefaultEncoder(), + } +} + +func freeSignContext(ctx *signContext) *signContext { + ctx.format = fmtCompact + for _, sb := range ctx.sigbuilders { + signatureBuilderPool.Put(sb) + } + ctx.sigbuilders = ctx.sigbuilders[:0] + ctx.detached = false + ctx.validateKey = false + ctx.encoder = base64.DefaultEncoder() + ctx.none = nil + ctx.payload = nil + + return ctx +} + +func (sc *signContext) ProcessOptions(options []SignOption) error { + for _, option := range options { + switch option.Ident() { + case identSerialization{}: + if err := option.Value(&sc.format); err != nil { + return signerr(`failed to retrieve serialization option value: %w`, err) + } + case identInsecureNoSignature{}: + var data withInsecureNoSignature + if err := option.Value(&data); err != nil { + return signerr(`failed to retrieve insecure-no-signature option value: %w`, err) + } + sb := signatureBuilderPool.Get() + sb.alg = jwa.NoSignature() + sb.protected = data.protected + sb.signer = noneSigner{} + sc.none = sb + sc.sigbuilders = append(sc.sigbuilders, sb) + case identKey{}: + var data *withKey + if err := option.Value(&data); err != nil { + return signerr(`jws.Sign: invalid value for WithKey option: %w`, err) + } + + alg, ok := data.alg.(jwa.SignatureAlgorithm) + if !ok { + return signerr(`expected algorithm to be of type jwa.SignatureAlgorithm but got (%[1]q, %[1]T)`, data.alg) + } + + // No, we don't accept "none" here. + if alg == jwa.NoSignature() { + return signerr(`"none" (jwa.NoSignature) cannot be used with jws.WithKey`) + } + + sb := signatureBuilderPool.Get() + sb.alg = alg + sb.protected = data.protected + sb.key = data.key + sb.public = data.public + + s2, err := SignerFor(alg) + if err == nil { + sb.signer2 = s2 + } else { + s1, err := legacySignerFor(alg) + if err != nil { + sb.signer2 = defaultSigner{alg: alg} + } else { + sb.signer = s1 + } + } + + sc.sigbuilders = append(sc.sigbuilders, sb) + case identDetachedPayload{}: + if sc.payload != nil { + return signerr(`payload must be nil when jws.WithDetachedPayload() is specified`) + } + if err := option.Value(&sc.payload); err != nil { + return signerr(`failed to retrieve detached payload option value: %w`, err) + } + sc.detached = true + case identValidateKey{}: + if err := option.Value(&sc.validateKey); err != nil { + return signerr(`failed to retrieve validate-key option value: %w`, err) + } + case identBase64Encoder{}: + if err := option.Value(&sc.encoder); err != nil { + return signerr(`failed to retrieve base64-encoder option value: %w`, err) + } + } + } + return nil +} + +func (sc *signContext) PopulateMessage(m *Message) error { + m.payload = sc.payload + m.signatures = make([]*Signature, 0, len(sc.sigbuilders)) + + for i, sb := range sc.sigbuilders { + // Create signature for each builders + if sc.validateKey { + if err := validateKeyBeforeUse(sb.key); err != nil { + return fmt.Errorf(`failed to validate key for signature %d: %w`, i, err) + } + } + + sig, err := sb.Build(sc, m.payload) + if err != nil { + return fmt.Errorf(`failed to build signature %d: %w`, i, err) + } + + m.signatures = append(m.signatures, sig) + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/signature_builder.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/signature_builder.go new file mode 100644 index 0000000000..fc09a69367 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/signature_builder.go @@ -0,0 +1,118 @@ +package jws + +import ( + "bytes" + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +var signatureBuilderPool = pool.New[*signatureBuilder](allocSignatureBuilder, freeSignatureBuilder) + +// signatureBuilder is a transient object that is used to build +// a single JWS signature. +// +// In a multi-signature JWS message, each message is paired with +// the following: +// - a signer (the object that takes a buffer and key and generates a signature) +// - a key (the key that is used to sign the payload) +// - protected headers (the headers that are protected by the signature) +// - public headers (the headers that are not protected by the signature) +// +// This object stores all of this information in one place. +// +// This object does NOT take care of any synchronization, because it is +// meant to be used in a single-threaded context. +type signatureBuilder struct { + alg jwa.SignatureAlgorithm + signer Signer + signer2 Signer2 + key any + protected Headers + public Headers +} + +func allocSignatureBuilder() *signatureBuilder { + return &signatureBuilder{} +} + +func freeSignatureBuilder(sb *signatureBuilder) *signatureBuilder { + sb.alg = jwa.EmptySignatureAlgorithm() + sb.signer = nil + sb.signer2 = nil + sb.key = nil + sb.protected = nil + sb.public = nil + return sb +} + +func (sb *signatureBuilder) Build(sc *signContext, payload []byte) (*Signature, error) { + protected := sb.protected + if protected == nil { + protected = NewHeaders() + } + + if err := protected.Set(AlgorithmKey, sb.alg); err != nil { + return nil, signerr(`failed to set "alg" header: %w`, err) + } + + if key, ok := sb.key.(jwk.Key); ok { + if kid, ok := key.KeyID(); ok && kid != "" { + if err := protected.Set(KeyIDKey, kid); err != nil { + return nil, signerr(`failed to set "kid" header: %w`, err) + } + } + } + + hdrs, err := mergeHeaders(sb.public, protected) + if err != nil { + return nil, signerr(`failed to merge headers: %w`, err) + } + + // raw, json format headers + hdrbuf, err := json.Marshal(hdrs) + if err != nil { + return nil, fmt.Errorf(`failed to marshal headers: %w`, err) + } + + // check if we need to base64 encode the payload + b64 := getB64Value(hdrs) + if !b64 && !sc.detached { + if bytes.IndexByte(payload, tokens.Period) != -1 { + return nil, fmt.Errorf(`payload must not contain a "."`) + } + } + + combined := jwsbb.SignBuffer(nil, hdrbuf, payload, sc.encoder, b64) + + var sig Signature + sig.protected = protected + sig.headers = sb.public + + if sb.signer2 != nil { + signature, err := sb.signer2.Sign(sb.key, combined) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload: %w`, err) + } + sig.signature = signature + return &sig, nil + } + + if sb.signer == nil { + panic("can't get here") + } + + signature, err := sb.signer.Sign(combined, sb.key) + if err != nil { + return nil, fmt.Errorf(`failed to sign payload: %w`, err) + } + + sig.signature = signature + + return &sig, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/signer.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/signer.go new file mode 100644 index 0000000000..340666931f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/signer.go @@ -0,0 +1,158 @@ +package jws + +import ( + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" +) + +// Signer2 is an interface that represents a per-signature algorithm signing +// operation. +type Signer2 interface { + Algorithm() jwa.SignatureAlgorithm + + // Sign takes a key and a payload, and returns the signature for the payload. + // The key type is restricted by the signature algorithm that this + // signer is associated with. + // + // (Note to users of legacy Signer interface: the method signature + // is different from the legacy Signer interface) + Sign(key any, payload []byte) ([]byte, error) +} + +var muSigner2DB sync.RWMutex +var signer2DB = make(map[jwa.SignatureAlgorithm]Signer2) + +type SignerFactory interface { + Create() (Signer, error) +} +type SignerFactoryFn func() (Signer, error) + +func (fn SignerFactoryFn) Create() (Signer, error) { + return fn() +} + +// SignerFor returns a Signer2 for the given signature algorithm. +// +// Currently, this function will never fail. It will always return a +// valid Signer2 object. The heuristic is as follows: +// 1. If a Signer2 is registered for the given algorithm, it will return that. +// 2. If a legacy Signer(Factory) is registered for the given algorithm, it will +// return a Signer2 that wraps the legacy Signer. +// 3. If no Signer2 or legacy Signer(Factory) is registered, it will return a +// default signer that uses jwsbb.Sign. +// +// jwsbb.Sign knows how to handle a static set of algorithms, so if the +// algorithm is not supported, it will return an error when you call +// `Sign` on the default signer. +func SignerFor(alg jwa.SignatureAlgorithm) (Signer2, error) { + muSigner2DB.RLock() + defer muSigner2DB.RUnlock() + + signer, ok := signer2DB[alg] + if ok { + return signer, nil + } + + s1, err := legacySignerFor(alg) + if err == nil { + return signerAdapter{signer: s1}, nil + } + + return defaultSigner{alg: alg}, nil +} + +var muSignerDB sync.RWMutex +var signerDB = make(map[jwa.SignatureAlgorithm]SignerFactory) + +// RegisterSigner is used to register a signer for the given +// algorithm. +// +// Please note that this function is intended to be passed a +// signer object as its second argument, but due to historical +// reasons the function signature is defined as taking `any` type. +// +// You should create a signer object that implements the `Signer2` +// interface to register a signer, unless you have legacy code that +// plugged into the `SignerFactory` interface. +// +// Unlike the `UnregisterSigner` function, this function automatically +// calls `jwa.RegisterSignatureAlgorithm` to register the algorithm +// in this module's algorithm database. +func RegisterSigner(alg jwa.SignatureAlgorithm, f any) error { + jwa.RegisterSignatureAlgorithm(alg) + switch s := f.(type) { + case Signer2: + muSigner2DB.Lock() + signer2DB[alg] = s + muSigner2DB.Unlock() + + // delete the other signer, if there was one + muSignerDB.Lock() + delete(signerDB, alg) + muSignerDB.Unlock() + case SignerFactory: + muSignerDB.Lock() + signerDB[alg] = s + muSignerDB.Unlock() + + // Remove previous signer, if there was one + removeSigner(alg) + + muSigner2DB.Lock() + delete(signer2DB, alg) + muSigner2DB.Unlock() + default: + return fmt.Errorf(`jws.RegisterSigner: unsupported type %T for algorithm %q`, f, alg) + } + return nil +} + +// UnregisterSigner removes the signer factory associated with +// the given algorithm, as well as the signer instance created +// by the factory. +// +// Note that when you call this function, the algorithm itself is +// not automatically unregistered from this module's algorithm database. +// This is because the algorithm may still be required for verification or +// some other operation (however unlikely, it is still possible). +// Therefore, in order to completely remove the algorithm, you must +// call `jwa.UnregisterSignatureAlgorithm` yourself. +func UnregisterSigner(alg jwa.SignatureAlgorithm) { + muSigner2DB.Lock() + delete(signer2DB, alg) + muSigner2DB.Unlock() + + muSignerDB.Lock() + delete(signerDB, alg) + muSignerDB.Unlock() + // Remove previous signer + removeSigner(alg) +} + +// NewSigner creates a signer that signs payloads using the given signature algorithm. +// This function is deprecated. You should use `SignerFor()` instead. +// +// This function only exists for backwards compatibility, but will not work +// unless you enable the legacy support mode by calling jws.Settings(jws.WithLegacySigners(true)). +func NewSigner(alg jwa.SignatureAlgorithm) (Signer, error) { + muSignerDB.RLock() + f, ok := signerDB[alg] + muSignerDB.RUnlock() + + if ok { + return f.Create() + } + return nil, fmt.Errorf(`jws.NewSigner: unsupported signature algorithm "%s"`, alg) +} + +type noneSigner struct{} + +func (noneSigner) Algorithm() jwa.SignatureAlgorithm { + return jwa.NoSignature() +} + +func (noneSigner) Sign([]byte, any) ([]byte, error) { + return nil, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/verifier.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/verifier.go new file mode 100644 index 0000000000..70b91c2938 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/verifier.go @@ -0,0 +1,154 @@ +package jws + +import ( + "fmt" + "sync" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +type defaultVerifier struct { + alg jwa.SignatureAlgorithm +} + +func (v defaultVerifier) Algorithm() jwa.SignatureAlgorithm { + return v.alg +} + +func (v defaultVerifier) Verify(key any, payload, signature []byte) error { + if err := jwsbb.Verify(key, v.alg.String(), payload, signature); err != nil { + return verifyError{verificationError{err}} + } + return nil +} + +type Verifier2 interface { + Verify(key any, payload, signature []byte) error +} + +var muVerifier2DB sync.RWMutex +var verifier2DB = make(map[jwa.SignatureAlgorithm]Verifier2) + +type verifierAdapter struct { + v Verifier +} + +func (v verifierAdapter) Verify(key any, payload, signature []byte) error { + if err := v.v.Verify(payload, signature, key); err != nil { + return verifyError{verificationError{err}} + } + return nil +} + +// VerifierFor returns a Verifier2 for the given signature algorithm. +// +// Currently, this function will never fail. It will always return a +// valid Verifier2 object. The heuristic is as follows: +// 1. If a Verifier2 is registered for the given algorithm, it will return that. +// 2. If a legacy Verifier(Factory) is registered for the given algorithm, it will +// return a Verifier2 that wraps the legacy Verifier. +// 3. If no Verifier2 or legacy Verifier(Factory) is registered, it will return a +// default verifier that uses jwsbb.Verify. +// +// jwsbb.Verify knows how to handle a static set of algorithms, so if the +// algorithm is not supported, it will return an error when you call +// `Verify` on the default verifier. +func VerifierFor(alg jwa.SignatureAlgorithm) (Verifier2, error) { + muVerifier2DB.RLock() + defer muVerifier2DB.RUnlock() + + v2, ok := verifier2DB[alg] + if ok { + return v2, nil + } + + v1, err := NewVerifier(alg) + if err == nil { + return verifierAdapter{v: v1}, nil + } + + return defaultVerifier{alg: alg}, nil +} + +type VerifierFactory interface { + Create() (Verifier, error) +} +type VerifierFactoryFn func() (Verifier, error) + +func (fn VerifierFactoryFn) Create() (Verifier, error) { + return fn() +} + +var muVerifierDB sync.RWMutex +var verifierDB = make(map[jwa.SignatureAlgorithm]VerifierFactory) + +// RegisterVerifier is used to register a verifier for the given +// algorithm. +// +// Please note that this function is intended to be passed a +// verifier object as its second argument, but due to historical +// reasons the function signature is defined as taking `any` type. +// +// You should create a signer object that implements the `Verifier2` +// interface to register a signer, unless you have legacy code that +// plugged into the `SignerFactory` interface. +// +// Unlike the `UnregisterVerifier` function, this function automatically +// calls `jwa.RegisterSignatureAlgorithm` to register the algorithm +// in this module's algorithm database. +func RegisterVerifier(alg jwa.SignatureAlgorithm, f any) error { + jwa.RegisterSignatureAlgorithm(alg) + switch v := f.(type) { + case Verifier2: + muVerifier2DB.Lock() + verifier2DB[alg] = v + muVerifier2DB.Unlock() + + muVerifierDB.Lock() + delete(verifierDB, alg) + muVerifierDB.Unlock() + case VerifierFactory: + muVerifierDB.Lock() + verifierDB[alg] = v + muVerifierDB.Unlock() + + muVerifier2DB.Lock() + delete(verifier2DB, alg) + muVerifier2DB.Unlock() + default: + return fmt.Errorf(`jws.RegisterVerifier: unsupported type %T for algorithm %q`, f, alg) + } + return nil +} + +// UnregisterVerifier removes the signer factory associated with +// the given algorithm. +// +// Note that when you call this function, the algorithm itself is +// not automatically unregistered from this module's algorithm database. +// This is because the algorithm may still be required for signing or +// some other operation (however unlikely, it is still possible). +// Therefore, in order to completely remove the algorithm, you must +// call `jwa.UnregisterSignatureAlgorithm` yourself. +func UnregisterVerifier(alg jwa.SignatureAlgorithm) { + muVerifier2DB.Lock() + delete(verifier2DB, alg) + muVerifier2DB.Unlock() + + muVerifierDB.Lock() + delete(verifierDB, alg) + muVerifierDB.Unlock() +} + +// NewVerifier creates a verifier that signs payloads using the given signature algorithm. +func NewVerifier(alg jwa.SignatureAlgorithm) (Verifier, error) { + muVerifierDB.RLock() + f, ok := verifierDB[alg] + muVerifierDB.RUnlock() + + if ok { + return f.Create() + } + return nil, fmt.Errorf(`jws.NewVerifier: unsupported signature algorithm "%s"`, alg) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jws/verify_context.go b/vendor/github.com/lestrrat-go/jwx/v3/jws/verify_context.go new file mode 100644 index 0000000000..b4807d569c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jws/verify_context.go @@ -0,0 +1,211 @@ +package jws + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +// verifyContext holds the state during JWS verification +type verifyContext struct { + parseOptions []ParseOption + dst *Message + detachedPayload []byte + keyProviders []KeyProvider + keyUsed any + validateKey bool + encoder Base64Encoder + //nolint:containedctx + ctx context.Context +} + +var verifyContextPool = pool.New[*verifyContext](allocVerifyContext, freeVerifyContext) + +func allocVerifyContext() *verifyContext { + return &verifyContext{ + encoder: base64.DefaultEncoder(), + ctx: context.Background(), + } +} + +func freeVerifyContext(vc *verifyContext) *verifyContext { + vc.parseOptions = vc.parseOptions[:0] + vc.dst = nil + vc.detachedPayload = nil + vc.keyProviders = vc.keyProviders[:0] + vc.keyUsed = nil + vc.validateKey = false + vc.encoder = base64.DefaultEncoder() + vc.ctx = context.Background() + return vc +} + +func (vc *verifyContext) ProcessOptions(options []VerifyOption) error { + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identMessage{}: + if err := option.Value(&vc.dst); err != nil { + return verifyerr(`invalid value for option WithMessage: %w`, err) + } + case identDetachedPayload{}: + if err := option.Value(&vc.detachedPayload); err != nil { + return verifyerr(`invalid value for option WithDetachedPayload: %w`, err) + } + case identKey{}: + var pair *withKey + if err := option.Value(&pair); err != nil { + return verifyerr(`invalid value for option WithKey: %w`, err) + } + vc.keyProviders = append(vc.keyProviders, &staticKeyProvider{ + alg: pair.alg.(jwa.SignatureAlgorithm), + key: pair.key, + }) + case identKeyProvider{}: + var kp KeyProvider + if err := option.Value(&kp); err != nil { + return verifyerr(`failed to retrieve key-provider option value: %w`, err) + } + vc.keyProviders = append(vc.keyProviders, kp) + case identKeyUsed{}: + if err := option.Value(&vc.keyUsed); err != nil { + return verifyerr(`failed to retrieve key-used option value: %w`, err) + } + case identContext{}: + if err := option.Value(&vc.ctx); err != nil { + return verifyerr(`failed to retrieve context option value: %w`, err) + } + case identValidateKey{}: + if err := option.Value(&vc.validateKey); err != nil { + return verifyerr(`failed to retrieve validate-key option value: %w`, err) + } + case identSerialization{}: + vc.parseOptions = append(vc.parseOptions, option.(ParseOption)) + case identBase64Encoder{}: + if err := option.Value(&vc.encoder); err != nil { + return verifyerr(`failed to retrieve base64-encoder option value: %w`, err) + } + default: + return verifyerr(`invalid jws.VerifyOption %q passed`, `With`+strings.TrimPrefix(fmt.Sprintf(`%T`, option.Ident()), `jws.ident`)) + } + } + + if len(vc.keyProviders) < 1 { + return verifyerr(`no key providers have been provided (see jws.WithKey(), jws.WithKeySet(), jws.WithVerifyAuto(), and jws.WithKeyProvider()`) + } + + return nil +} + +func (vc *verifyContext) VerifyMessage(buf []byte) ([]byte, error) { + msg, err := Parse(buf, vc.parseOptions...) + if err != nil { + return nil, verifyerr(`failed to parse jws: %w`, err) + } + defer msg.clearRaw() + + if vc.detachedPayload != nil { + if len(msg.payload) != 0 { + return nil, verifyerr(`can't specify detached payload for JWS with payload`) + } + + msg.payload = vc.detachedPayload + } + + verifyBuf := pool.ByteSlice().Get() + + // Because deferred functions bind to the current value of the variable, + // we can't just use `defer pool.ByteSlice().Put(verifyBuf)` here. + // Instead, we use a closure to reference the _variable_. + // it would be better if we could call it directly, but there are + // too many place we may return from this function + defer func() { + pool.ByteSlice().Put(verifyBuf) + }() + + errs := pool.ErrorSlice().Get() + defer func() { + pool.ErrorSlice().Put(errs) + }() + for idx, sig := range msg.signatures { + var rawHeaders []byte + if rbp, ok := sig.protected.(interface{ rawBuffer() []byte }); ok { + if raw := rbp.rawBuffer(); raw != nil { + rawHeaders = raw + } + } + + if rawHeaders == nil { + protected, err := json.Marshal(sig.protected) + if err != nil { + return nil, verifyerr(`failed to marshal "protected" for signature #%d: %w`, idx+1, err) + } + rawHeaders = protected + } + + verifyBuf = verifyBuf[:0] + verifyBuf = jwsbb.SignBuffer(verifyBuf, rawHeaders, msg.payload, vc.encoder, msg.b64) + for i, kp := range vc.keyProviders { + var sink algKeySink + if err := kp.FetchKeys(vc.ctx, &sink, sig, msg); err != nil { + return nil, verifyerr(`key provider %d failed: %w`, i, err) + } + + for _, pair := range sink.list { + // alg is converted here because pair.alg is of type jwa.KeyAlgorithm. + // this may seem ugly, but we're trying to avoid declaring separate + // structs for `alg jwa.KeyEncryptionAlgorithm` and `alg jwa.SignatureAlgorithm` + //nolint:forcetypeassert + alg := pair.alg.(jwa.SignatureAlgorithm) + key := pair.key + + if err := vc.tryKey(verifyBuf, alg, key, msg, sig); err != nil { + errs = append(errs, verifyerr(`failed to verify signature #%d with key %T: %w`, idx+1, key, err)) + continue + } + + return msg.payload, nil + } + } + errs = append(errs, verifyerr(`signature #%d could not be verified with any of the keys`, idx+1)) + } + return nil, verifyerr(`could not verify message using any of the signatures or keys: %w`, errors.Join(errs...)) +} + +func (vc *verifyContext) tryKey(verifyBuf []byte, alg jwa.SignatureAlgorithm, key any, msg *Message, sig *Signature) error { + if vc.validateKey { + if err := validateKeyBeforeUse(key); err != nil { + return fmt.Errorf(`failed to validate key before signing: %w`, err) + } + } + + verifier, err := VerifierFor(alg) + if err != nil { + return fmt.Errorf(`failed to get verifier for algorithm %q: %w`, alg, err) + } + + if err := verifier.Verify(key, verifyBuf, sig.signature); err != nil { + return verificationError{err} + } + + // Verification succeeded + if vc.keyUsed != nil { + if err := blackmagic.AssignIfCompatible(vc.keyUsed, key); err != nil { + return fmt.Errorf(`failed to assign used key (%T) to %T: %w`, key, vc.keyUsed, err) + } + } + + if vc.dst != nil { + *(vc.dst) = *msg + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwt/BUILD.bazel new file mode 100644 index 0000000000..86197d348a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/BUILD.bazel @@ -0,0 +1,72 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "jwt", + srcs = [ + "builder_gen.go", + "errors.go", + "filter.go", + "fastpath.go", + "http.go", + "interface.go", + "io.go", + "jwt.go", + "options.go", + "options_gen.go", + "serialize.go", + "token_gen.go", + "token_options.go", + "token_options_gen.go", + "validate.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwt", + visibility = ["//visibility:public"], + deps = [ + "//:jwx", + "//internal/base64", + "//transform", + "//internal/json", + "//internal/tokens", + "//internal/pool", + "//jwa", + "//jwe", + "//jwk", + "//jws", + "//jws/jwsbb", + "//jwt/internal/types", + "//jwt/internal/errors", + "@com_github_lestrrat_go_blackmagic//:blackmagic", + "@com_github_lestrrat_go_option_v2//:option", + ], +) + +go_test( + name = "jwt_test", + srcs = [ + "jwt_test.go", + "options_gen_test.go", + "token_options_test.go", + "token_test.go", + "validate_test.go", + "verify_test.go", + ], + embed = [":jwt"], + deps = [ + "//internal/json", + "//internal/jwxtest", + "//jwa", + "//jwe", + "//jwk", + "//jwk/ecdsa", + "//jws", + "//jwt/internal/types", + "@com_github_lestrrat_go_httprc_v3//:httprc", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":jwt", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/README.md b/vendor/github.com/lestrrat-go/jwx/v3/jwt/README.md new file mode 100644 index 0000000000..a6b5664c94 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/README.md @@ -0,0 +1,224 @@ +# JWT [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v3/jwt.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v3/jwt) + +Package jwt implements JSON Web Tokens as described in [RFC7519](https://tools.ietf.org/html/rfc7519). + +* Convenience methods for oft-used keys ("aud", "sub", "iss", etc) +* Convenience functions to extract/parse from http.Request, http.Header, url.Values +* Ability to Get/Set arbitrary keys +* Conversion to and from JSON +* Generate signed tokens +* Verify signed tokens +* Extra support for OpenID tokens via [github.com/lestrrat-go/jwx/v3/jwt/openid](./jwt/openid) + +How-to style documentation can be found in the [docs directory](../docs). + +More examples are located in the examples directory ([jwt_example_test.go](../examples/jwt_example_test.go)) + +# SYNOPSIS + +## Verify a signed JWT + +```go + token, err := jwt.Parse(payload, jwt.WithKey(alg, key)) + if err != nil { + fmt.Printf("failed to parse payload: %s\n", err) + } +``` + +## Token Usage + +```go +func ExampleJWT() { + const aLongLongTimeAgo = 233431200 + + t := jwt.New() + t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/v3/jwt`) + t.Set(jwt.AudienceKey, `Golang Users`) + t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0)) + t.Set(`privateClaimKey`, `Hello, World!`) + + buf, err := json.MarshalIndent(t, "", " ") + if err != nil { + fmt.Printf("failed to generate JSON: %s\n", err) + return + } + + fmt.Printf("%s\n", buf) + fmt.Printf("aud -> '%s'\n", t.Audience()) + fmt.Printf("iat -> '%s'\n", t.IssuedAt().Format(time.RFC3339)) + if v, ok := t.Get(`privateClaimKey`); ok { + fmt.Printf("privateClaimKey -> '%s'\n", v) + } + fmt.Printf("sub -> '%s'\n", t.Subject()) + + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Printf("failed to generate private key: %s", err) + return + } + + { + // Signing a token (using raw rsa.PrivateKey) + signed, err := jwt.Sign(t, jwt.WithKey(jwa.RS256, key)) + if err != nil { + log.Printf("failed to sign token: %s", err) + return + } + _ = signed + } + + { + // Signing a token (using JWK) + jwkKey, err := jwk.New(key) + if err != nil { + log.Printf("failed to create JWK key: %s", err) + return + } + + signed, err := jwt.Sign(t, jwt.WithKey(jwa.RS256, jwkKey)) + if err != nil { + log.Printf("failed to sign token: %s", err) + return + } + _ = signed + } +} +``` + +## OpenID Claims + +`jwt` package can work with token types other than the default one. +For OpenID claims, use the token created by `openid.New()`, or +use the `jwt.WithToken(openid.New())`. If you need to use other specialized +claims, use `jwt.WithToken()` to specify the exact token type + +```go +func Example_openid() { + const aLongLongTimeAgo = 233431200 + + t := openid.New() + t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/v3/jwt`) + t.Set(jwt.AudienceKey, `Golang Users`) + t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0)) + t.Set(`privateClaimKey`, `Hello, World!`) + + addr := openid.NewAddress() + addr.Set(openid.AddressPostalCodeKey, `105-0011`) + addr.Set(openid.AddressCountryKey, `日本`) + addr.Set(openid.AddressRegionKey, `東京都`) + addr.Set(openid.AddressLocalityKey, `港区`) + addr.Set(openid.AddressStreetAddressKey, `芝公園 4-2-8`) + t.Set(openid.AddressKey, addr) + + buf, err := json.MarshalIndent(t, "", " ") + if err != nil { + fmt.Printf("failed to generate JSON: %s\n", err) + return + } + fmt.Printf("%s\n", buf) + + t2, err := jwt.Parse(buf, jwt.WithToken(openid.New())) + if err != nil { + fmt.Printf("failed to parse JSON: %s\n", err) + return + } + if _, ok := t2.(openid.Token); !ok { + fmt.Printf("using jwt.WithToken(openid.New()) creates an openid.Token instance") + return + } +} +``` + +# FAQ + +## Why is `jwt.Token` an interface? + +In this package, `jwt.Token` is an interface. This is not an arbitrary choice: there are actual reason for the type being an interface. + +We understand that if you are migrating from another library this may be a deal breaker, but we hope you can at least appreciate the fact that this was not done arbitrarily, and that there were real technical trade offs that were evaluated. + +### No uninitialized tokens + +First and foremost, by making it an interface, you cannot use an uninitialized token: + +```go +var token1 jwt.Token // this is nil, you can't just start using this +if err := json.Unmarshal(data, &token1); err != nil { // so you can't do this + ... +} + +// But you _can_ do this, and we _want_ you to do this so the object is properly initialized +token2 = jwt.New() +if err := json.Unmarshal(data, &token2); err != nil { // actually, in practice you should use jwt.Parse() + .... +} +``` + +### But why does it need to be initialized? + +There are several reasons, but one of the reasons is that I'm using a sync.Mutex to avoid races. We want this to be properly initialized. + +The other reason is that we support custom claims out of the box. The `map[string]interface{}` container is initialized during new. This is important when checking for equality using reflect-y methods (akin to `reflect.DeepEqual`), because if you allowed zero values, you could end up with "empty" tokens, that actually differ. Consider the following: + +```go +// assume jwt.Token was s struct, not an interface +token1 := jwt.Token{ privateClaims: make(map[string]interface{}) } +token2 := jwt.Token{ privateClaims: nil } +``` + +These are semantically equivalent, but users would need to be aware of this difference when comparing values. By forcing the user to use a constructor, we can force a uniform empty state. + +### Standard way to store values + +Unlike some other libraries, this library allows you to store standard claims and non-standard claims in the same token. + +You _want_ to store standard claims in a properly typed field, which we do for fields like "iss", "nbf", etc. +But for non-standard claims, there is just no way of doing this, so we _have_ to use a container like `map[string]interface{}` + +This means that if you allow direct access to these fields via a struct, you will have two different ways to access the claims, which is confusing: + +```go +tok.Issuer = ... +tok.PrivateClaims["foo"] = ... +``` + +So we want to hide where this data is stored, and use a standard method like `Set()` and `Get()` to store all the values. +At this point you are effectively going to hide the implementation detail from the user, so you end up with a struct like below, which is fundamentally not so different from providing just an interface{}: + +```go +type Token struct { + // unexported fields +} + +func (tok *Token) Set(...) { ... } +``` + +### Use of pointers to store values + +We wanted to differentiate the state between a claim being uninitialized, and a claim being initialized to empty. + +So we use pointers to store values: + +```go +type stdToken struct { + .... + issuer *string // if nil, uninitialized. if &(""), initialized to empty +} +``` + +This is fine for us, but we doubt that this would be something users would want to do. +This is a subtle difference, but cluttering up the API with slight variations of the same type (i.e. pointers vs non-pointers) seemed like a bad idea to us. + +```go +token.Issuer = &issuer // want to avoid this + +token.Set(jwt.IssuerKey, "foobar") // so this is what we picked +``` + +This way users no longer need to care how the data is internally stored. + +### Allow more than one type of token through the same interface + +`dgrijalva/jwt-go` does this in a different way, but we felt that it would be more intuitive for all tokens to follow a single interface so there is fewer type conversions required. + +See the `openid` token for an example. diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/builder_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/builder_gen.go new file mode 100644 index 0000000000..48d0375a28 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/builder_gen.go @@ -0,0 +1,88 @@ +// Code generated by tools/cmd/genjwt/main.go. DO NOT EDIT. + +package jwt + +import ( + "fmt" + "sync" + "time" +) + +// Builder is a convenience wrapper around the New() constructor +// and the Set() methods to assign values to Token claims. +// Users can successively call Claim() on the Builder, and have it +// construct the Token when Build() is called. This alleviates the +// need for the user to check for the return value of every single +// Set() method call. +// Note that each call to Claim() overwrites the value set from the +// previous call. +type Builder struct { + mu sync.Mutex + claims map[string]any +} + +func NewBuilder() *Builder { + return &Builder{} +} + +func (b *Builder) init() { + if b.claims == nil { + b.claims = make(map[string]any) + } +} + +func (b *Builder) Claim(name string, value any) *Builder { + b.mu.Lock() + defer b.mu.Unlock() + b.init() + b.claims[name] = value + return b +} + +func (b *Builder) Audience(v []string) *Builder { + return b.Claim(AudienceKey, v) +} + +func (b *Builder) Expiration(v time.Time) *Builder { + return b.Claim(ExpirationKey, v) +} + +func (b *Builder) IssuedAt(v time.Time) *Builder { + return b.Claim(IssuedAtKey, v) +} + +func (b *Builder) Issuer(v string) *Builder { + return b.Claim(IssuerKey, v) +} + +func (b *Builder) JwtID(v string) *Builder { + return b.Claim(JwtIDKey, v) +} + +func (b *Builder) NotBefore(v time.Time) *Builder { + return b.Claim(NotBeforeKey, v) +} + +func (b *Builder) Subject(v string) *Builder { + return b.Claim(SubjectKey, v) +} + +// Build creates a new token based on the claims that the builder has received +// so far. If a claim cannot be set, then the method returns a nil Token with +// a en error as a second return value +// +// Once `Build()` is called, all claims are cleared from the Builder, and the +// Builder can be reused to build another token +func (b *Builder) Build() (Token, error) { + b.mu.Lock() + claims := b.claims + b.claims = nil + b.mu.Unlock() + tok := New() + for k, v := range claims { + if err := tok.Set(k, v); err != nil { + return nil, fmt.Errorf(`failed to set claim %q: %w`, k, err) + } + } + return tok, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/errors.go new file mode 100644 index 0000000000..c5b529c1ae --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/errors.go @@ -0,0 +1,95 @@ +package jwt + +import ( + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" +) + +// ClaimNotFoundError returns the opaque error value that is returned when +// `jwt.Get` fails to find the requested claim. +// +// This value should only be used for comparison using `errors.Is()`. +func ClaimNotFoundError() error { + return jwterrs.ErrClaimNotFound +} + +// ClaimAssignmentFailedError returns the opaque error value that is returned +// when `jwt.Get` fails to assign the value to the destination. For example, +// this can happen when the value is a string, but you passed a &int as the +// destination. +// +// This value should only be used for comparison using `errors.Is()`. +func ClaimAssignmentFailedError() error { + return jwterrs.ErrClaimAssignmentFailed +} + +// UnknownPayloadTypeError returns the opaque error value that is returned when +// `jwt.Parse` fails due to not being able to deduce the format of +// the incoming buffer. +// +// This value should only be used for comparison using `errors.Is()`. +func UnknownPayloadTypeError() error { + return jwterrs.ErrUnknownPayloadType +} + +// ParseError returns the opaque error that is returned from jwt.Parse when +// the input is not a valid JWT. +// +// This value should only be used for comparison using `errors.Is()`. +func ParseError() error { + return jwterrs.ErrParse +} + +// ValidateError returns the immutable error used for validation errors +// +// This value should only be used for comparison using `errors.Is()`. +func ValidateError() error { + return jwterrs.ErrValidateDefault +} + +// InvalidIssuerError returns the immutable error used when `iss` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func InvalidIssuerError() error { + return jwterrs.ErrInvalidIssuerDefault +} + +// TokenExpiredError returns the immutable error used when `exp` claim +// is not satisfied. +// +// This value should only be used for comparison using `errors.Is()`. +func TokenExpiredError() error { + return jwterrs.ErrTokenExpiredDefault +} + +// InvalidIssuedAtError returns the immutable error used when `iat` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func InvalidIssuedAtError() error { + return jwterrs.ErrInvalidIssuedAtDefault +} + +// TokenNotYetValidError returns the immutable error used when `nbf` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func TokenNotYetValidError() error { + return jwterrs.ErrTokenNotYetValidDefault +} + +// InvalidAudienceError returns the immutable error used when `aud` claim +// is not satisfied +// +// This value should only be used for comparison using `errors.Is()`. +func InvalidAudienceError() error { + return jwterrs.ErrInvalidAudienceDefault +} + +// MissingRequiredClaimError returns the immutable error used when the claim +// specified by `jwt.IsRequired()` is not present. +// +// This value should only be used for comparison using `errors.Is()`. +func MissingRequiredClaimError() error { + return jwterrs.ErrMissingRequiredClaimDefault +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/fastpath.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/fastpath.go new file mode 100644 index 0000000000..43f7c966da --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/fastpath.go @@ -0,0 +1,71 @@ +package jwt + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/base64" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" +) + +// signFast reinvents the wheel a bit to avoid the overhead of +// going through the entire jws.Sign() machinery. +func signFast(t Token, alg jwa.SignatureAlgorithm, key any) ([]byte, error) { + algstr := alg.String() + + var kid string + if jwkKey, ok := key.(jwk.Key); ok { + if v, ok := jwkKey.KeyID(); ok && v != "" { + kid = v + } + } + + // Setup headers + // {"alg":"","typ":"JWT"} + // 1234567890123456789012 + want := len(algstr) + 22 + // also, if kid != "", we need to add "kid":"$kid" + if kid != "" { + // "kid":"" + // 12345689 + want += len(kid) + 9 + } + hdr := pool.ByteSlice().GetCapacity(want) + hdr = append(hdr, '{', '"', 'a', 'l', 'g', '"', ':', '"') + hdr = append(hdr, algstr...) + hdr = append(hdr, '"') + if kid != "" { + hdr = append(hdr, ',', '"', 'k', 'i', 'd', '"', ':', '"') + hdr = append(hdr, kid...) + hdr = append(hdr, '"') + } + hdr = append(hdr, ',', '"', 't', 'y', 'p', '"', ':', '"', 'J', 'W', 'T', '"', '}') + defer pool.ByteSlice().Put(hdr) + + // setup the buffer to sign with + payload, err := json.Marshal(t) + if err != nil { + return nil, fmt.Errorf(`jwt.signFast: failed to marshal token payload: %w`, err) + } + + combined := jwsbb.SignBuffer(nil, hdr, payload, base64.DefaultEncoder(), true) + signer, err := jws.SignerFor(alg) + if err != nil { + return nil, fmt.Errorf(`jwt.signFast: failed to get signer for %s: %w`, alg, err) + } + + signature, err := signer.Sign(key, combined) + if err != nil { + return nil, fmt.Errorf(`jwt.signFast: failed to sign payload with %s: %w`, alg, err) + } + + serialized, err := jwsbb.JoinCompact(nil, hdr, payload, signature, base64.DefaultEncoder(), true) + if err != nil { + return nil, fmt.Errorf("jwt.signFast: failed to join compact: %w", err) + } + return serialized, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/filter.go new file mode 100644 index 0000000000..31471dbdfb --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/filter.go @@ -0,0 +1,34 @@ +package jwt + +import ( + "github.com/lestrrat-go/jwx/v3/transform" +) + +// TokenFilter is an interface that allows users to filter JWT claims. +// It provides two methods: Filter and Reject; Filter returns a new token with only +// the claims that match the filter criteria, while Reject returns a new token with +// only the claims that DO NOT match the filter. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type TokenFilter interface { + Filter(token Token) (Token, error) + Reject(token Token) (Token, error) +} + +// StandardClaimsFilter returns a TokenFilter that filters out standard JWT claims. +// +// You can use this filter to create tokens that either only has standard claims +// or only custom claims. If you need to configure the filter more precisely, consider +// using the ClaimNameFilter directly. +func StandardClaimsFilter() TokenFilter { + return stdClaimsFilter +} + +var stdClaimsFilter = NewClaimNameFilter(stdClaimNames...) + +// NewClaimNameFilter creates a new ClaimNameFilter with the specified claim names. +func NewClaimNameFilter(names ...string) TokenFilter { + return transform.NewNameBasedFilter[Token](names...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/http.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/http.go new file mode 100644 index 0000000000..691c5a0df4 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/http.go @@ -0,0 +1,295 @@ +package jwt + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +// ParseCookie parses a JWT stored in a http.Cookie with the given name. +// If the specified cookie is not found, http.ErrNoCookie is returned. +func ParseCookie(req *http.Request, name string, options ...ParseOption) (Token, error) { + var dst **http.Cookie + for _, option := range options { + switch option.Ident() { + case identCookie{}: + if err := option.Value(&dst); err != nil { + return nil, fmt.Errorf(`jws.ParseCookie: value to option WithCookie must be **http.Cookie: %w`, err) + } + } + } + + cookie, err := req.Cookie(name) + if err != nil { + return nil, err + } + tok, err := ParseString(cookie.Value, options...) + if err != nil { + return nil, fmt.Errorf(`jws.ParseCookie: failed to parse token stored in cookie: %w`, err) + } + + if dst != nil { + *dst = cookie + } + return tok, nil +} + +// ParseHeader parses a JWT stored in a http.Header. +// +// For the header "Authorization", it will strip the prefix "Bearer " and will +// treat the remaining value as a JWT. +func ParseHeader(hdr http.Header, name string, options ...ParseOption) (Token, error) { + key := http.CanonicalHeaderKey(name) + v := strings.TrimSpace(hdr.Get(key)) + if v == "" { + return nil, fmt.Errorf(`empty header (%s)`, key) + } + + if key == "Authorization" { + // Authorization header is an exception. We strip the "Bearer " from + // the prefix + v = strings.TrimSpace(strings.TrimPrefix(v, "Bearer")) + } + + tok, err := ParseString(v, options...) + if err != nil { + return nil, fmt.Errorf(`failed to parse token stored in header (%s): %w`, key, err) + } + return tok, nil +} + +// ParseForm parses a JWT stored in a url.Value. +func ParseForm(values url.Values, name string, options ...ParseOption) (Token, error) { + v := strings.TrimSpace(values.Get(name)) + if v == "" { + return nil, fmt.Errorf(`empty value (%s)`, name) + } + + return ParseString(v, options...) +} + +// ParseRequest searches a http.Request object for a JWT token. +// +// Specifying WithHeaderKey() will tell it to search under a specific +// header key. Specifying WithFormKey() will tell it to search under +// a specific form field. +// +// If none of jwt.WithHeaderKey()/jwt.WithCookieKey()/jwt.WithFormKey() is +// used, "Authorization" header will be searched. If any of these options +// are specified, you must explicitly re-enable searching for "Authorization" header +// if you also want to search for it. +// +// # searches for "Authorization" +// jwt.ParseRequest(req) +// +// # searches for "x-my-token" ONLY. +// jwt.ParseRequest(req, jwt.WithHeaderKey("x-my-token")) +// +// # searches for "Authorization" AND "x-my-token" +// jwt.ParseRequest(req, jwt.WithHeaderKey("Authorization"), jwt.WithHeaderKey("x-my-token")) +// +// Cookies are searched using (http.Request).Cookie(). If you have multiple +// cookies with the same name, and you want to search for a specific one that +// (http.Request).Cookie() would not return, you will need to implement your +// own logic to extract the cookie and use jwt.ParseString(). +func ParseRequest(req *http.Request, options ...ParseOption) (Token, error) { + var hdrkeys []string + var formkeys []string + var cookiekeys []string + var parseOptions []ParseOption + for _, option := range options { + switch option.Ident() { + case identHeaderKey{}: + var v string + if err := option.Value(&v); err != nil { + return nil, fmt.Errorf(`jws.ParseRequest: value to option WithHeaderKey must be string: %w`, err) + } + hdrkeys = append(hdrkeys, v) + case identFormKey{}: + var v string + if err := option.Value(&v); err != nil { + return nil, fmt.Errorf(`jws.ParseRequest: value to option WithFormKey must be string: %w`, err) + } + formkeys = append(formkeys, v) + case identCookieKey{}: + var v string + if err := option.Value(&v); err != nil { + return nil, fmt.Errorf(`jws.ParseRequest: value to option WithCookieKey must be string: %w`, err) + } + cookiekeys = append(cookiekeys, v) + default: + parseOptions = append(parseOptions, option) + } + } + + if len(hdrkeys) == 0 && len(formkeys) == 0 && len(cookiekeys) == 0 { + hdrkeys = append(hdrkeys, "Authorization") + } + + mhdrs := pool.KeyToErrorMap().Get() + defer pool.KeyToErrorMap().Put(mhdrs) + mfrms := pool.KeyToErrorMap().Get() + defer pool.KeyToErrorMap().Put(mfrms) + mcookies := pool.KeyToErrorMap().Get() + defer pool.KeyToErrorMap().Put(mcookies) + + for _, hdrkey := range hdrkeys { + // Check presence via a direct map lookup + if _, ok := req.Header[http.CanonicalHeaderKey(hdrkey)]; !ok { + // if non-existent, not error + continue + } + + tok, err := ParseHeader(req.Header, hdrkey, parseOptions...) + if err != nil { + mhdrs[hdrkey] = err + continue + } + return tok, nil + } + + for _, name := range cookiekeys { + tok, err := ParseCookie(req, name, parseOptions...) + if err != nil { + if err == http.ErrNoCookie { + // not fatal + mcookies[name] = err + } + continue + } + return tok, nil + } + + if cl := req.ContentLength; cl > 0 { + if err := req.ParseForm(); err != nil { + return nil, fmt.Errorf(`failed to parse form: %w`, err) + } + } + + for _, formkey := range formkeys { + // Check presence via a direct map lookup + if _, ok := req.Form[formkey]; !ok { + // if non-existent, not error + continue + } + + tok, err := ParseForm(req.Form, formkey, parseOptions...) + if err != nil { + mfrms[formkey] = err + continue + } + return tok, nil + } + + // Everything below is a prelude to error reporting. + var triedHdrs strings.Builder + for i, hdrkey := range hdrkeys { + if i > 0 { + triedHdrs.WriteString(", ") + } + triedHdrs.WriteString(strconv.Quote(hdrkey)) + } + + var triedForms strings.Builder + for i, formkey := range formkeys { + if i > 0 { + triedForms.WriteString(", ") + } + triedForms.WriteString(strconv.Quote(formkey)) + } + + var triedCookies strings.Builder + for i, cookiekey := range cookiekeys { + if i > 0 { + triedCookies.WriteString(", ") + } + triedCookies.WriteString(strconv.Quote(cookiekey)) + } + + var b strings.Builder + b.WriteString(`failed to find a valid token in any location of the request (tried: `) + olen := b.Len() + if triedHdrs.Len() > 0 { + b.WriteString(`header keys: [`) + b.WriteString(triedHdrs.String()) + b.WriteByte(tokens.CloseSquareBracket) + } + if triedForms.Len() > 0 { + if b.Len() > olen { + b.WriteString(", ") + } + b.WriteString("form keys: [") + b.WriteString(triedForms.String()) + b.WriteByte(tokens.CloseSquareBracket) + } + + if triedCookies.Len() > 0 { + if b.Len() > olen { + b.WriteString(", ") + } + b.WriteString("cookie keys: [") + b.WriteString(triedCookies.String()) + b.WriteByte(tokens.CloseSquareBracket) + } + b.WriteByte(')') + + lmhdrs := len(mhdrs) + lmfrms := len(mfrms) + lmcookies := len(mcookies) + var errors []any + if lmhdrs > 0 || lmfrms > 0 || lmcookies > 0 { + b.WriteString(". Additionally, errors were encountered during attempts to verify using:") + + if lmhdrs > 0 { + b.WriteString(" headers: (") + count := 0 + for hdrkey, err := range mhdrs { + if count > 0 { + b.WriteString(", ") + } + b.WriteString("[header key: ") + b.WriteString(strconv.Quote(hdrkey)) + b.WriteString(", error: %w]") + errors = append(errors, err) + count++ + } + b.WriteString(")") + } + + if lmcookies > 0 { + count := 0 + b.WriteString(" cookies: (") + for cookiekey, err := range mcookies { + if count > 0 { + b.WriteString(", ") + } + b.WriteString("[cookie key: ") + b.WriteString(strconv.Quote(cookiekey)) + b.WriteString(", error: %w]") + errors = append(errors, err) + count++ + } + } + + if lmfrms > 0 { + count := 0 + b.WriteString(" forms: (") + for formkey, err := range mfrms { + if count > 0 { + b.WriteString(", ") + } + b.WriteString("[form key: ") + b.WriteString(strconv.Quote(formkey)) + b.WriteString(", error: %w]") + errors = append(errors, err) + count++ + } + } + } + return nil, fmt.Errorf(b.String(), errors...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/interface.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/interface.go new file mode 100644 index 0000000000..f9a9d971ef --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/interface.go @@ -0,0 +1,8 @@ +package jwt + +import ( + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +type DecodeCtx = json.DecodeCtx +type TokenWithDecodeCtx = json.DecodeCtxContainer diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/BUILD.bazel new file mode 100644 index 0000000000..a053e8c0aa --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "errors", + srcs = [ + "errors.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwt/internal/errors", + visibility = ["//jwt:__subpackages__"], +) + +alias( + name = "go_default_library", + actual = ":errors", + visibility = ["//jwt:__subpackages__"], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/errors.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/errors.go new file mode 100644 index 0000000000..a1dca0d5a3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/errors/errors.go @@ -0,0 +1,183 @@ +// Package errors exist to store errors for jwt and openid packages. +// +// It's internal because we don't want to expose _anything_ about these errors +// so users absolutely cannot do anything other than use them as opaque errors. +package errors + +import ( + "errors" + "fmt" +) + +var ( + ErrClaimNotFound = ClaimNotFoundError{} + ErrClaimAssignmentFailed = ClaimAssignmentFailedError{Err: errors.New(`claim assignment failed`)} + ErrUnknownPayloadType = errors.New(`unknown payload type (payload is not JWT?)`) + ErrParse = ParseError{error: errors.New(`jwt.Parse: unknown error`)} + ErrValidateDefault = ValidationError{errors.New(`unknown error`)} + ErrInvalidIssuerDefault = InvalidIssuerError{errors.New(`"iss" not satisfied`)} + ErrTokenExpiredDefault = TokenExpiredError{errors.New(`"exp" not satisfied: token is expired`)} + ErrInvalidIssuedAtDefault = InvalidIssuedAtError{errors.New(`"iat" not satisfied`)} + ErrTokenNotYetValidDefault = TokenNotYetValidError{errors.New(`"nbf" not satisfied: token is not yet valid`)} + ErrInvalidAudienceDefault = InvalidAudienceError{errors.New(`"aud" not satisfied`)} + ErrMissingRequiredClaimDefault = &MissingRequiredClaimError{error: errors.New(`required claim is missing`)} +) + +type ClaimNotFoundError struct { + Name string +} + +func (e ClaimNotFoundError) Error() string { + // This error message uses "field" instead of "claim" for backwards compatibility, + // but it shuold really be "claim" since it refers to a JWT claim. + return fmt.Sprintf(`field "%s" not found`, e.Name) +} + +func (e ClaimNotFoundError) Is(target error) bool { + _, ok := target.(ClaimNotFoundError) + return ok +} + +type ClaimAssignmentFailedError struct { + Err error +} + +func (e ClaimAssignmentFailedError) Error() string { + // This error message probably should be tweaked, but it is this way + // for backwards compatibility. + return fmt.Sprintf(`failed to assign value to dst: %s`, e.Err.Error()) +} + +func (e ClaimAssignmentFailedError) Unwrap() error { + return e.Err +} + +func (e ClaimAssignmentFailedError) Is(target error) bool { + _, ok := target.(ClaimAssignmentFailedError) + return ok +} + +type ParseError struct { + error +} + +func (e ParseError) Unwrap() error { + return e.error +} + +func (ParseError) Is(err error) bool { + _, ok := err.(ParseError) + return ok +} + +func ParseErrorf(prefix, f string, args ...any) error { + return ParseError{fmt.Errorf(prefix+": "+f, args...)} +} + +type ValidationError struct { + error +} + +func (ValidationError) Is(err error) bool { + _, ok := err.(ValidationError) + return ok +} + +func (err ValidationError) Unwrap() error { + return err.error +} + +func ValidateErrorf(f string, args ...any) error { + return ValidationError{fmt.Errorf(`jwt.Validate: `+f, args...)} +} + +type InvalidIssuerError struct { + error +} + +func (err InvalidIssuerError) Is(target error) bool { + _, ok := target.(InvalidIssuerError) + return ok +} + +func (err InvalidIssuerError) Unwrap() error { + return err.error +} + +func IssuerErrorf(f string, args ...any) error { + return InvalidIssuerError{fmt.Errorf(`"iss" not satisfied: `+f, args...)} +} + +type TokenExpiredError struct { + error +} + +func (err TokenExpiredError) Is(target error) bool { + _, ok := target.(TokenExpiredError) + return ok +} + +func (err TokenExpiredError) Unwrap() error { + return err.error +} + +type InvalidIssuedAtError struct { + error +} + +func (err InvalidIssuedAtError) Is(target error) bool { + _, ok := target.(InvalidIssuedAtError) + return ok +} + +func (err InvalidIssuedAtError) Unwrap() error { + return err.error +} + +type TokenNotYetValidError struct { + error +} + +func (err TokenNotYetValidError) Is(target error) bool { + _, ok := target.(TokenNotYetValidError) + return ok +} + +func (err TokenNotYetValidError) Unwrap() error { + return err.error +} + +type InvalidAudienceError struct { + error +} + +func (err InvalidAudienceError) Is(target error) bool { + _, ok := target.(InvalidAudienceError) + return ok +} + +func (err InvalidAudienceError) Unwrap() error { + return err.error +} + +func AudienceErrorf(f string, args ...any) error { + return InvalidAudienceError{fmt.Errorf(`"aud" not satisfied: `+f, args...)} +} + +type MissingRequiredClaimError struct { + error + + claim string +} + +func (err *MissingRequiredClaimError) Is(target error) bool { + err1, ok := target.(*MissingRequiredClaimError) + if !ok { + return false + } + return err1 == ErrMissingRequiredClaimDefault || err1.claim == err.claim +} + +func MissingRequiredClaimErrorf(name string) error { + return &MissingRequiredClaimError{claim: name, error: fmt.Errorf(`required claim "%s" is missing`, name)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/BUILD.bazel new file mode 100644 index 0000000000..1d046a3ecc --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/BUILD.bazel @@ -0,0 +1,35 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "types", + srcs = [ + "date.go", + "string.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/jwt/internal/types", + visibility = ["//jwt:__subpackages__"], + deps = [ + "//internal/json", + "//internal/tokens", + ], +) + +go_test( + name = "types_test", + srcs = [ + "date_test.go", + "string_test.go", + ], + deps = [ + ":types", + "//internal/json", + "//jwt", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":types", + visibility = ["//jwt:__subpackages__"], +) diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/date.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/date.go new file mode 100644 index 0000000000..3d40a9ed97 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/date.go @@ -0,0 +1,192 @@ +package types + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/tokens" +) + +const ( + DefaultPrecision uint32 = 0 // second level + MaxPrecision uint32 = 9 // nanosecond level +) + +var Pedantic uint32 +var ParsePrecision = DefaultPrecision +var FormatPrecision = DefaultPrecision + +// NumericDate represents the date format used in the 'nbf' claim +type NumericDate struct { + time.Time +} + +func (n *NumericDate) Get() time.Time { + if n == nil { + return (time.Time{}).UTC() + } + return n.Time +} + +func intToTime(v any, t *time.Time) bool { + var n int64 + switch x := v.(type) { + case int64: + n = x + case int32: + n = int64(x) + case int16: + n = int64(x) + case int8: + n = int64(x) + case int: + n = int64(x) + default: + return false + } + + *t = time.Unix(n, 0) + return true +} + +func parseNumericString(x string) (time.Time, error) { + var t time.Time // empty time for empty return value + + // Only check for the escape hatch if it's the pedantic + // flag is off + if Pedantic != 1 { + // This is an escape hatch for non-conformant providers + // that gives us RFC3339 instead of epoch time + for _, r := range x { + // 0x30 = '0', 0x39 = '9', 0x2E = tokens.Period + if (r >= 0x30 && r <= 0x39) || r == 0x2E { + continue + } + + // if it got here, then it probably isn't epoch time + tv, err := time.Parse(time.RFC3339, x) + if err != nil { + return t, fmt.Errorf(`value is not number of seconds since the epoch, and attempt to parse it as RFC3339 timestamp failed: %w`, err) + } + return tv, nil + } + } + + var fractional string + whole := x + if i := strings.IndexRune(x, tokens.Period); i > 0 { + if ParsePrecision > 0 && len(x) > i+1 { + fractional = x[i+1:] // everything after the tokens.Period + if int(ParsePrecision) < len(fractional) { + // Remove insignificant digits + fractional = fractional[:int(ParsePrecision)] + } + // Replace missing fractional diits with zeros + for len(fractional) < int(MaxPrecision) { + fractional = fractional + "0" + } + } + whole = x[:i] + } + n, err := strconv.ParseInt(whole, 10, 64) + if err != nil { + return t, fmt.Errorf(`failed to parse whole value %q: %w`, whole, err) + } + var nsecs int64 + if fractional != "" { + v, err := strconv.ParseInt(fractional, 10, 64) + if err != nil { + return t, fmt.Errorf(`failed to parse fractional value %q: %w`, fractional, err) + } + nsecs = v + } + + return time.Unix(n, nsecs).UTC(), nil +} + +func (n *NumericDate) Accept(v any) error { + var t time.Time + switch x := v.(type) { + case float32: + tv, err := parseNumericString(fmt.Sprintf(`%.9f`, x)) + if err != nil { + return fmt.Errorf(`failed to accept float32 %.9f: %w`, x, err) + } + t = tv + case float64: + tv, err := parseNumericString(fmt.Sprintf(`%.9f`, x)) + if err != nil { + return fmt.Errorf(`failed to accept float32 %.9f: %w`, x, err) + } + t = tv + case json.Number: + tv, err := parseNumericString(x.String()) + if err != nil { + return fmt.Errorf(`failed to accept json.Number %q: %w`, x.String(), err) + } + t = tv + case string: + tv, err := parseNumericString(x) + if err != nil { + return fmt.Errorf(`failed to accept string %q: %w`, x, err) + } + t = tv + case time.Time: + t = x + default: + if !intToTime(v, &t) { + return fmt.Errorf(`invalid type %T`, v) + } + } + n.Time = t.UTC() + return nil +} + +func (n NumericDate) String() string { + if FormatPrecision == 0 { + return strconv.FormatInt(n.Unix(), 10) + } + + // This is cheating, but it's better (easier) than doing floating point math + // We basically munge with strings after formatting an integer value + // for nanoseconds since epoch + s := strconv.FormatInt(n.UnixNano(), 10) + for len(s) < int(MaxPrecision) { + s = "0" + s + } + + slwhole := len(s) - int(MaxPrecision) + s = s[:slwhole] + "." + s[slwhole:slwhole+int(FormatPrecision)] + if s[0] == tokens.Period { + s = "0" + s + } + + return s +} + +// MarshalJSON translates from internal representation to JSON NumericDate +// See https://tools.ietf.org/html/rfc7519#page-6 +func (n *NumericDate) MarshalJSON() ([]byte, error) { + if n.IsZero() { + return json.Marshal(nil) + } + + return json.Marshal(n.String()) +} + +func (n *NumericDate) UnmarshalJSON(data []byte) error { + var v any + if err := json.Unmarshal(data, &v); err != nil { + return fmt.Errorf(`failed to unmarshal date: %w`, err) + } + + var n2 NumericDate + if err := n2.Accept(v); err != nil { + return fmt.Errorf(`invalid value for NumericDate: %w`, err) + } + *n = n2 + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/string.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/string.go new file mode 100644 index 0000000000..8117bea358 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/internal/types/string.go @@ -0,0 +1,43 @@ +package types + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +type StringList []string + +func (l StringList) Get() []string { + return []string(l) +} + +func (l *StringList) Accept(v any) error { + switch x := v.(type) { + case string: + *l = StringList([]string{x}) + case []string: + *l = StringList(x) + case []any: + list := make(StringList, len(x)) + for i, e := range x { + if s, ok := e.(string); ok { + list[i] = s + continue + } + return fmt.Errorf(`invalid list element type %T`, e) + } + *l = list + default: + return fmt.Errorf(`invalid type: %T`, v) + } + return nil +} + +func (l *StringList) UnmarshalJSON(data []byte) error { + var v any + if err := json.Unmarshal(data, &v); err != nil { + return fmt.Errorf(`failed to unmarshal data: %w`, err) + } + return l.Accept(v) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/io.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/io.go new file mode 100644 index 0000000000..812cda775e --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/io.go @@ -0,0 +1,42 @@ +// Code generated by tools/cmd/genreadfile/main.go. DO NOT EDIT. + +package jwt + +import ( + "fmt" + "io/fs" + "os" +) + +type sysFS struct{} + +func (sysFS) Open(path string) (fs.File, error) { + return os.Open(path) +} + +func ReadFile(path string, options ...ReadFileOption) (Token, error) { + var parseOptions []ParseOption + for _, option := range options { + if po, ok := option.(ParseOption); ok { + parseOptions = append(parseOptions, po) + } + } + + var srcFS fs.FS = sysFS{} + for _, option := range options { + switch option.Ident() { + case identFS{}: + if err := option.Value(&srcFS); err != nil { + return nil, fmt.Errorf("failed to set fs.FS: %w", err) + } + } + } + + f, err := srcFS.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + return ParseReader(f, parseOptions...) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/jwt.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/jwt.go new file mode 100644 index 0000000000..43e382987a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/jwt.go @@ -0,0 +1,592 @@ +//go:generate ../tools/cmd/genjwt.sh +//go:generate stringer -type=TokenOption -output=token_options_gen.go + +// Package jwt implements JSON Web Tokens as described in https://tools.ietf.org/html/rfc7519 +package jwt + +import ( + "bytes" + "fmt" + "io" + "sync/atomic" + "time" + + "github.com/lestrrat-go/jwx/v3" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws" + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" + "github.com/lestrrat-go/jwx/v3/jwt/internal/types" +) + +var defaultTruncation atomic.Int64 + +// Settings controls global settings that are specific to JWTs. +func Settings(options ...GlobalOption) { + var flattenAudience bool + var parsePedantic bool + var parsePrecision = types.MaxPrecision + 1 // illegal value, so we can detect nothing was set + var formatPrecision = types.MaxPrecision + 1 // illegal value, so we can detect nothing was set + truncation := time.Duration(-1) + for _, option := range options { + switch option.Ident() { + case identTruncation{}: + if err := option.Value(&truncation); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithTruncation must be time.Duration: %s", err)) + } + case identFlattenAudience{}: + if err := option.Value(&flattenAudience); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithFlattenAudience must be bool: %s", err)) + } + case identNumericDateParsePedantic{}: + if err := option.Value(&parsePedantic); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithNumericDateParsePedantic must be bool: %s", err)) + } + case identNumericDateParsePrecision{}: + var v int + if err := option.Value(&v); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithNumericDateParsePrecision must be int: %s", err)) + } + // only accept this value if it's in our desired range + if v >= 0 && v <= int(types.MaxPrecision) { + parsePrecision = uint32(v) + } + case identNumericDateFormatPrecision{}: + var v int + if err := option.Value(&v); err != nil { + panic(fmt.Sprintf("jwt.Settings: value for WithNumericDateFormatPrecision must be int: %s", err)) + } + // only accept this value if it's in our desired range + if v >= 0 && v <= int(types.MaxPrecision) { + formatPrecision = uint32(v) + } + } + } + + if parsePrecision <= types.MaxPrecision { // remember we set default to max + 1 + v := atomic.LoadUint32(&types.ParsePrecision) + if v != parsePrecision { + atomic.CompareAndSwapUint32(&types.ParsePrecision, v, parsePrecision) + } + } + + if formatPrecision <= types.MaxPrecision { // remember we set default to max + 1 + v := atomic.LoadUint32(&types.FormatPrecision) + if v != formatPrecision { + atomic.CompareAndSwapUint32(&types.FormatPrecision, v, formatPrecision) + } + } + + { + v := atomic.LoadUint32(&types.Pedantic) + if (v == 1) != parsePedantic { + var newVal uint32 + if parsePedantic { + newVal = 1 + } + atomic.CompareAndSwapUint32(&types.Pedantic, v, newVal) + } + } + + { + defaultOptionsMu.Lock() + if flattenAudience { + defaultOptions.Enable(FlattenAudience) + } else { + defaultOptions.Disable(FlattenAudience) + } + defaultOptionsMu.Unlock() + } + + if truncation >= 0 { + defaultTruncation.Store(int64(truncation)) + } +} + +var registry = json.NewRegistry() + +// ParseString calls Parse against a string +func ParseString(s string, options ...ParseOption) (Token, error) { + tok, err := parseBytes([]byte(s), options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseString`, `failed to parse string: %w`, err) + } + return tok, nil +} + +// Parse parses the JWT token payload and creates a new `jwt.Token` object. +// The token must be encoded in JWS compact format, or a raw JSON form of JWT +// without any signatures. +// +// If you need JWE support on top of JWS, you will need to rollout your +// own workaround. +// +// If the token is signed, and you want to verify the payload matches the signature, +// you must pass the jwt.WithKey(alg, key) or jwt.WithKeySet(jwk.Set) option. +// If you do not specify these parameters, no verification will be performed. +// +// During verification, if the JWS headers specify a key ID (`kid`), the +// key used for verification must match the specified ID. If you are somehow +// using a key without a `kid` (which is highly unlikely if you are working +// with a JWT from a well-know provider), you can work around this by modifying +// the `jwk.Key` and setting the `kid` header. +// +// If you also want to assert the validity of the JWT itself (i.e. expiration +// and such), use the `Validate()` function on the returned token, or pass the +// `WithValidate(true)` option. Validate options can also be passed to +// `Parse` +// +// This function takes both ParseOption and ValidateOption types: +// ParseOptions control the parsing behavior, and ValidateOptions are +// passed to `Validate()` when `jwt.WithValidate` is specified. +func Parse(s []byte, options ...ParseOption) (Token, error) { + tok, err := parseBytes(s, options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.Parse`, `failed to parse token: %w`, err) + } + return tok, nil +} + +// ParseInsecure is exactly the same as Parse(), but it disables +// signature verification and token validation. +// +// You cannot override `jwt.WithVerify()` or `jwt.WithValidate()` +// using this function. Providing these options would result in +// an error +func ParseInsecure(s []byte, options ...ParseOption) (Token, error) { + for _, option := range options { + switch option.Ident() { + case identVerify{}, identValidate{}: + return nil, jwterrs.ParseErrorf(`jwt.ParseInsecure`, `jwt.WithVerify() and jwt.WithValidate() may not be specified`) + } + } + + options = append(options, WithVerify(false), WithValidate(false)) + tok, err := Parse(s, options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseInsecure`, `failed to parse token: %w`, err) + } + return tok, nil +} + +// ParseReader calls Parse against an io.Reader +func ParseReader(src io.Reader, options ...ParseOption) (Token, error) { + // We're going to need the raw bytes regardless. Read it. + data, err := io.ReadAll(src) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseReader`, `failed to read from token data source: %w`, err) + } + tok, err := parseBytes(data, options...) + if err != nil { + return nil, jwterrs.ParseErrorf(`jwt.ParseReader`, `failed to parse token: %w`, err) + } + return tok, nil +} + +type parseCtx struct { + token Token + validateOpts []ValidateOption + verifyOpts []jws.VerifyOption + localReg *json.Registry + pedantic bool + skipVerification bool + validate bool + withKeyCount int + withKey *withKey // this is used to detect if we have a WithKey option +} + +func parseBytes(data []byte, options ...ParseOption) (Token, error) { + var ctx parseCtx + + // Validation is turned on by default. You need to specify + // jwt.WithValidate(false) if you want to disable it + ctx.validate = true + + // Verification is required (i.e., it is assumed that the incoming + // data is in JWS format) unless the user explicitly asks for + // it to be skipped. + verification := true + + var verifyOpts []Option + for _, o := range options { + if v, ok := o.(ValidateOption); ok { + ctx.validateOpts = append(ctx.validateOpts, v) + continue + } + + switch o.Ident() { + case identKey{}: + // it would be nice to be able to detect if ctx.verifyOpts[0] + // is a WithKey option, but unfortunately at that point we have + // already converted the options to a jws option, which means + // we can no longer compare its Ident() to jwt.identKey{}. + // So let's just count this here + ctx.withKeyCount++ + if ctx.withKeyCount == 1 { + if err := o.Value(&ctx.withKey); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithKey option must be a *jwt.withKey: %w", err) + } + } + verifyOpts = append(verifyOpts, o) + case identKeySet{}, identVerifyAuto{}, identKeyProvider{}, identBase64Encoder{}: + verifyOpts = append(verifyOpts, o) + case identToken{}: + var token Token + if err := o.Value(&token); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithToken option must be a jwt.Token: %w", err) + } + ctx.token = token + case identPedantic{}: + if err := o.Value(&ctx.pedantic); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithPedantic option must be a bool: %w", err) + } + case identValidate{}: + if err := o.Value(&ctx.validate); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithValidate option must be a bool: %w", err) + } + case identVerify{}: + if err := o.Value(&verification); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithVerify option must be a bool: %w", err) + } + case identTypedClaim{}: + var pair claimPair + if err := o.Value(&pair); err != nil { + return nil, fmt.Errorf("jws.parseBytes: value for WithTypedClaim option must be claimPair: %w", err) + } + if ctx.localReg == nil { + ctx.localReg = json.NewRegistry() + } + ctx.localReg.Register(pair.Name, pair.Value) + } + } + + if !verification { + ctx.skipVerification = true + } + + lvo := len(verifyOpts) + if lvo == 0 && verification { + return nil, fmt.Errorf(`jwt.Parse: no keys for verification are provided (use jwt.WithVerify(false) to explicitly skip)`) + } + + if lvo > 0 { + converted, err := toVerifyOptions(verifyOpts...) + if err != nil { + return nil, fmt.Errorf(`jwt.Parse: failed to convert options into jws.VerifyOption: %w`, err) + } + ctx.verifyOpts = converted + } + + data = bytes.TrimSpace(data) + return parse(&ctx, data) +} + +const ( + _JwsVerifyInvalid = iota + _JwsVerifyDone + _JwsVerifyExpectNested + _JwsVerifySkipped +) + +var _ = _JwsVerifyInvalid + +func verifyJWS(ctx *parseCtx, payload []byte) ([]byte, int, error) { + lvo := len(ctx.verifyOpts) + if lvo == 0 { + return nil, _JwsVerifySkipped, nil + } + + if lvo == 1 && ctx.withKeyCount == 1 { + wk := ctx.withKey + alg, ok := wk.alg.(jwa.SignatureAlgorithm) + if ok && len(wk.options) == 0 { + verified, err := jws.VerifyCompactFast(wk.key, payload, alg) + if err != nil { + return nil, _JwsVerifyDone, err + } + return verified, _JwsVerifyDone, nil + } + } + + verifyOpts := append(ctx.verifyOpts, jws.WithCompact()) + verified, err := jws.Verify(payload, verifyOpts...) + return verified, _JwsVerifyDone, err +} + +// verify parameter exists to make sure that we don't accidentally skip +// over verification just because alg == "" or key == nil or something. +func parse(ctx *parseCtx, data []byte) (Token, error) { + payload := data + const maxDecodeLevels = 2 + + // If cty = `JWT`, we expect this to be a nested structure + var expectNested bool + +OUTER: + for i := range maxDecodeLevels { + switch kind := jwx.GuessFormat(payload); kind { + case jwx.JWT: + if ctx.pedantic { + if expectNested { + return nil, fmt.Errorf(`expected nested encrypted/signed payload, got raw JWT`) + } + } + + if i == 0 { + // We were NOT enveloped in other formats + if !ctx.skipVerification { + if _, _, err := verifyJWS(ctx, payload); err != nil { + return nil, err + } + } + } + + break OUTER + case jwx.InvalidFormat: + return nil, UnknownPayloadTypeError() + case jwx.UnknownFormat: + // "Unknown" may include invalid JWTs, for example, those who lack "aud" + // claim. We could be pedantic and reject these + if ctx.pedantic { + return nil, fmt.Errorf(`unknown JWT format (pedantic)`) + } + + if i == 0 { + // We were NOT enveloped in other formats + if !ctx.skipVerification { + if _, _, err := verifyJWS(ctx, payload); err != nil { + return nil, err + } + } + } + break OUTER + case jwx.JWS: + // Food for thought: This is going to break if you have multiple layers of + // JWS enveloping using different keys. It is highly unlikely use case, + // but it might happen. + + // skipVerification should only be set to true by us. It's used + // when we just want to parse the JWT out of a payload + if !ctx.skipVerification { + // nested return value means: + // false (next envelope _may_ need to be processed) + // true (next envelope MUST be processed) + v, state, err := verifyJWS(ctx, payload) + if err != nil { + return nil, err + } + + if state != _JwsVerifySkipped { + payload = v + + // We only check for cty and typ if the pedantic flag is enabled + if !ctx.pedantic { + continue + } + + if state == _JwsVerifyExpectNested { + expectNested = true + continue OUTER + } + + // if we're not nested, we found our target. bail out of this loop + break OUTER + } + } + + // No verification. + m, err := jws.Parse(data, jws.WithCompact()) + if err != nil { + return nil, fmt.Errorf(`invalid jws message: %w`, err) + } + payload = m.Payload() + default: + return nil, fmt.Errorf(`unsupported format (layer: #%d)`, i+1) + } + expectNested = false + } + + if ctx.token == nil { + ctx.token = New() + } + + if ctx.localReg != nil { + dcToken, ok := ctx.token.(TokenWithDecodeCtx) + if !ok { + return nil, fmt.Errorf(`typed claim was requested, but the token (%T) does not support DecodeCtx`, ctx.token) + } + dc := json.NewDecodeCtx(ctx.localReg) + dcToken.SetDecodeCtx(dc) + defer func() { dcToken.SetDecodeCtx(nil) }() + } + + if err := json.Unmarshal(payload, ctx.token); err != nil { + return nil, fmt.Errorf(`failed to parse token: %w`, err) + } + + if ctx.validate { + if err := Validate(ctx.token, ctx.validateOpts...); err != nil { + return nil, err + } + } + return ctx.token, nil +} + +// Sign is a convenience function to create a signed JWT token serialized in +// compact form. +// +// It accepts either a raw key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) +// or a jwk.Key, and the name of the algorithm that should be used to sign +// the token. +// +// For well-known algorithms with no special considerations (e.g. detached +// payloads, extra protected heders, etc), this function will automatically +// take the fast path and bypass the jws.Sign() machinery, which improves +// performance significantly. +// +// If the key is a jwk.Key and the key contains a key ID (`kid` field), +// then it is added to the protected header generated by the signature +// +// The algorithm specified in the `alg` parameter must be able to support +// the type of key you provided, otherwise an error is returned. +// For convenience `alg` is of type jwa.KeyAlgorithm so you can pass +// the return value of `(jwk.Key).Algorithm()` directly, but in practice +// it must be an instance of jwa.SignatureAlgorithm, otherwise an error +// is returned. +// +// The protected header will also automatically have the `typ` field set +// to the literal value `JWT`, unless you provide a custom value for it +// by jws.WithProtectedHeaders option, that can be passed to `jwt.WithKey“. +func Sign(t Token, options ...SignOption) ([]byte, error) { + // fast path; can only happen if there is exactly one option + if len(options) == 1 && (options[0].Ident() == identKey{}) { + // The option must be a withKey option. + var wk *withKey + if err := options[0].Value(&wk); err == nil { + alg, ok := wk.alg.(jwa.SignatureAlgorithm) + if !ok { + return nil, fmt.Errorf(`jwt.Sign: invalid algorithm type %T. jwa.SignatureAlgorithm is required`, wk.alg) + } + + // Check if option contains anything other than alg/key + if len(wk.options) == 0 { + // yay, we have something we can put in the FAST PATH! + return signFast(t, alg, wk.key) + } + // fallthrough + } + // fallthrough + } + + var soptions []jws.SignOption + if l := len(options); l > 0 { + // we need to from SignOption to Option because ... reasons + // (todo: when go1.18 prevails, use type parameters + rawoptions := make([]Option, l) + for i, option := range options { + rawoptions[i] = option + } + + converted, err := toSignOptions(rawoptions...) + if err != nil { + return nil, fmt.Errorf(`jwt.Sign: failed to convert options into jws.SignOption: %w`, err) + } + soptions = converted + } + return NewSerializer().sign(soptions...).Serialize(t) +} + +// Equal compares two JWT tokens. Do not use `reflect.Equal` or the like +// to compare tokens as they will also compare extra detail such as +// sync.Mutex objects used to control concurrent access. +// +// The comparison for values is currently done using a simple equality ("=="), +// except for time.Time, which uses time.Equal after dropping the monotonic +// clock and truncating the values to 1 second accuracy. +// +// if both t1 and t2 are nil, returns true +func Equal(t1, t2 Token) bool { + if t1 == nil && t2 == nil { + return true + } + + // we already checked for t1 == t2 == nil, so safe to do this + if t1 == nil || t2 == nil { + return false + } + + j1, err := json.Marshal(t1) + if err != nil { + return false + } + + j2, err := json.Marshal(t2) + if err != nil { + return false + } + + return bytes.Equal(j1, j2) +} + +func (t *stdToken) Clone() (Token, error) { + dst := New() + + dst.Options().Set(*(t.Options())) + for _, k := range t.Keys() { + var v any + if err := t.Get(k, &v); err != nil { + return nil, fmt.Errorf(`jwt.Clone: failed to get %s: %w`, k, err) + } + if err := dst.Set(k, v); err != nil { + return nil, fmt.Errorf(`jwt.Clone failed to set %s: %w`, k, err) + } + } + return dst, nil +} + +type CustomDecoder = json.CustomDecoder +type CustomDecodeFunc = json.CustomDecodeFunc + +// RegisterCustomField allows users to specify that a private field +// be decoded as an instance of the specified type. This option has +// a global effect. +// +// For example, suppose you have a custom field `x-birthday`, which +// you want to represent as a string formatted in RFC3339 in JSON, +// but want it back as `time.Time`. +// +// In such case you would register a custom field as follows +// +// jwt.RegisterCustomField(`x-birthday`, time.Time{}) +// +// Then you can use a `time.Time` variable to extract the value +// of `x-birthday` field, instead of having to use `any` +// and later convert it to `time.Time` +// +// var bday time.Time +// _ = token.Get(`x-birthday`, &bday) +// +// If you need a more fine-tuned control over the decoding process, +// you can register a `CustomDecoder`. For example, below shows +// how to register a decoder that can parse RFC822 format string: +// +// jwt.RegisterCustomField(`x-birthday`, jwt.CustomDecodeFunc(func(data []byte) (any, error) { +// return time.Parse(time.RFC822, string(data)) +// })) +// +// Please note that use of custom fields can be problematic if you +// are using a library that does not implement MarshalJSON/UnmarshalJSON +// and you try to roundtrip from an object to JSON, and then back to an object. +// For example, in the above example, you can _parse_ time values formatted +// in the format specified in RFC822, but when you convert an object into +// JSON, it will be formatted in RFC3339, because that's what `time.Time` +// likes to do. To avoid this, it's always better to use a custom type +// that wraps your desired type (in this case `time.Time`) and implement +// MarshalJSON and UnmashalJSON. +func RegisterCustomField(name string, object any) { + registry.Register(name, object) +} + +func getDefaultTruncation() time.Duration { + return time.Duration(defaultTruncation.Load()) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.go new file mode 100644 index 0000000000..cadf163b15 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.go @@ -0,0 +1,322 @@ +package jwt + +import ( + "fmt" + "time" + + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/option/v2" +) + +type identInsecureNoSignature struct{} +type identKey struct{} +type identKeySet struct{} +type identTypedClaim struct{} +type identVerifyAuto struct{} + +func toSignOptions(options ...Option) ([]jws.SignOption, error) { + soptions := make([]jws.SignOption, 0, len(options)) + for _, option := range options { + switch option.Ident() { + case identInsecureNoSignature{}: + soptions = append(soptions, jws.WithInsecureNoSignature()) + case identKey{}: + var wk withKey + if err := option.Value(&wk); err != nil { + return nil, fmt.Errorf(`toSignOtpions: failed to convert option value to withKey: %w`, err) + } + var wksoptions []jws.WithKeySuboption + for _, subopt := range wk.options { + wksopt, ok := subopt.(jws.WithKeySuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jws.WithKeySuboption, but got %T`, subopt) + } + wksoptions = append(wksoptions, wksopt) + } + + soptions = append(soptions, jws.WithKey(wk.alg, wk.key, wksoptions...)) + case identSignOption{}: + var sigOpt jws.SignOption + if err := option.Value(&sigOpt); err != nil { + return nil, fmt.Errorf(`failed to decode SignOption: %w`, err) + } + soptions = append(soptions, sigOpt) + case identBase64Encoder{}: + var enc jws.Base64Encoder + if err := option.Value(&enc); err != nil { + return nil, fmt.Errorf(`failed to decode Base64Encoder: %w`, err) + } + soptions = append(soptions, jws.WithBase64Encoder(enc)) + } + } + return soptions, nil +} + +func toEncryptOptions(options ...Option) ([]jwe.EncryptOption, error) { + soptions := make([]jwe.EncryptOption, 0, len(options)) + for _, option := range options { + switch option.Ident() { + case identKey{}: + var wk withKey + if err := option.Value(&wk); err != nil { + return nil, fmt.Errorf(`toEncryptOptions: failed to convert option value to withKey: %w`, err) + } + var wksoptions []jwe.WithKeySuboption + for _, subopt := range wk.options { + wksopt, ok := subopt.(jwe.WithKeySuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jwe.WithKeySuboption, but got %T`, subopt) + } + wksoptions = append(wksoptions, wksopt) + } + + soptions = append(soptions, jwe.WithKey(wk.alg, wk.key, wksoptions...)) + case identEncryptOption{}: + var encOpt jwe.EncryptOption + if err := option.Value(&encOpt); err != nil { + return nil, fmt.Errorf(`failed to decode EncryptOption: %w`, err) + } + soptions = append(soptions, encOpt) + } + } + return soptions, nil +} + +func toVerifyOptions(options ...Option) ([]jws.VerifyOption, error) { + voptions := make([]jws.VerifyOption, 0, len(options)) + for _, option := range options { + switch option.Ident() { + case identKey{}: + var wk withKey + if err := option.Value(&wk); err != nil { + return nil, fmt.Errorf(`toVerifyOptions: failed to convert option value to withKey: %w`, err) + } + var wksoptions []jws.WithKeySuboption + for _, subopt := range wk.options { + wksopt, ok := subopt.(jws.WithKeySuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jws.WithKeySuboption, but got %T`, subopt) + } + wksoptions = append(wksoptions, wksopt) + } + + voptions = append(voptions, jws.WithKey(wk.alg, wk.key, wksoptions...)) + case identKeySet{}: + var wks withKeySet + if err := option.Value(&wks); err != nil { + return nil, fmt.Errorf(`failed to convert option value to withKeySet: %w`, err) + } + var wkssoptions []jws.WithKeySetSuboption + for _, subopt := range wks.options { + wkssopt, ok := subopt.(jws.WithKeySetSuboption) + if !ok { + return nil, fmt.Errorf(`expected optional arguments in jwt.WithKey to be jws.WithKeySetSuboption, but got %T`, subopt) + } + wkssoptions = append(wkssoptions, wkssopt) + } + + voptions = append(voptions, jws.WithKeySet(wks.set, wkssoptions...)) + case identVerifyAuto{}: + var vo jws.VerifyOption + if err := option.Value(&vo); err != nil { + return nil, fmt.Errorf(`failed to decode VerifyOption: %w`, err) + } + voptions = append(voptions, vo) + case identKeyProvider{}: + var kp jws.KeyProvider + if err := option.Value(&kp); err != nil { + return nil, fmt.Errorf(`failed to decode KeyProvider: %w`, err) + } + voptions = append(voptions, jws.WithKeyProvider(kp)) + case identBase64Encoder{}: + var enc jws.Base64Encoder + if err := option.Value(&enc); err != nil { + return nil, fmt.Errorf(`failed to decode Base64Encoder: %w`, err) + } + voptions = append(voptions, jws.WithBase64Encoder(enc)) + } + } + return voptions, nil +} + +type withKey struct { + alg jwa.KeyAlgorithm + key any + options []Option +} + +// WithKey is a multipurpose option. It can be used for either jwt.Sign, jwt.Parse (and +// its siblings), and jwt.Serializer methods. For signatures, please see the documentation +// for `jws.WithKey` for more details. For encryption, please see the documentation +// for `jwe.WithKey`. +// +// It is the caller's responsibility to match the suboptions to the operation that they +// are performing. For example, you are not allowed to do this, because the operation +// is to generate a signature, and yet you are passing options for jwe: +// +// jwt.Sign(token, jwt.WithKey(alg, key, jweOptions...)) +// +// In the above example, the creation of the option via `jwt.WithKey()` will work, but +// when `jwt.Sign()` is called, the fact that you passed JWE suboptions will be +// detected, and an error will occur. +func WithKey(alg jwa.KeyAlgorithm, key any, suboptions ...Option) SignEncryptParseOption { + return &signEncryptParseOption{option.New(identKey{}, &withKey{ + alg: alg, + key: key, + options: suboptions, + })} +} + +type withKeySet struct { + set jwk.Set + options []any +} + +// WithKeySet forces the Parse method to verify the JWT message +// using one of the keys in the given key set. +// +// Key IDs (`kid`) in the JWS message and the JWK in the given `jwk.Set` +// must match in order for the key to be a candidate to be used for +// verification. +// +// This is for security reasons. If you must disable it, you can do so by +// specifying `jws.WithRequireKid(false)` in the suboptions. But we don't +// recommend it unless you know exactly what the security implications are +// +// When using this option, keys MUST have a proper 'alg' field +// set. This is because we need to know the exact algorithm that +// you (the user) wants to use to verify the token. We do NOT +// trust the token's headers, because they can easily be tampered with. +// +// However, there _is_ a workaround if you do understand the risks +// of allowing a library to automatically choose a signature verification strategy, +// and you do not mind the verification process having to possibly +// attempt using multiple times before succeeding to verify. See +// `jws.InferAlgorithmFromKey` option +// +// If you have only one key in the set, and are sure you want to +// use that key, you can use the `jwt.WithDefaultKey` option. +func WithKeySet(set jwk.Set, options ...any) ParseOption { + return &parseOption{option.New(identKeySet{}, &withKeySet{ + set: set, + options: options, + })} +} + +// WithIssuer specifies that expected issuer value. If not specified, +// the value of issuer is not verified at all. +func WithIssuer(s string) ValidateOption { + return WithValidator(issuerClaimValueIs(s)) +} + +// WithSubject specifies that expected subject value. If not specified, +// the value of subject is not verified at all. +func WithSubject(s string) ValidateOption { + return WithValidator(ClaimValueIs(SubjectKey, s)) +} + +// WithJwtID specifies that expected jti value. If not specified, +// the value of jti is not verified at all. +func WithJwtID(s string) ValidateOption { + return WithValidator(ClaimValueIs(JwtIDKey, s)) +} + +// WithAudience specifies that expected audience value. +// `Validate()` will return true if one of the values in the `aud` element +// matches this value. If not specified, the value of `aud` is not +// verified at all. +func WithAudience(s string) ValidateOption { + return WithValidator(audienceClaimContainsString(s)) +} + +// WithClaimValue specifies the expected value for a given claim +func WithClaimValue(name string, v any) ValidateOption { + return WithValidator(ClaimValueIs(name, v)) +} + +// WithTypedClaim allows a private claim to be parsed into the object type of +// your choice. It works much like the RegisterCustomField, but the effect +// is only applicable to the jwt.Parse function call which receives this option. +// +// While this can be extremely useful, this option should be used with caution: +// There are many caveats that your entire team/user-base needs to be aware of, +// and therefore in general its use is discouraged. Only use it when you know +// what you are doing, and you document its use clearly for others. +// +// First and foremost, this is a "per-object" option. Meaning that given the same +// serialized format, it is possible to generate two objects whose internal +// representations may differ. That is, if you parse one _WITH_ the option, +// and the other _WITHOUT_, their internal representation may completely differ. +// This could potentially lead to problems. +// +// Second, specifying this option will slightly slow down the decoding process +// as it needs to consult multiple definitions sources (global and local), so +// be careful if you are decoding a large number of tokens, as the effects will stack up. +// +// Finally, this option will also NOT work unless the tokens themselves support such +// parsing mechanism. For example, while tokens obtained from `jwt.New()` and +// `openid.New()` will respect this option, if you provide your own custom +// token type, it will need to implement the TokenWithDecodeCtx interface. +func WithTypedClaim(name string, object any) ParseOption { + return &parseOption{option.New(identTypedClaim{}, claimPair{Name: name, Value: object})} +} + +// WithRequiredClaim specifies that the claim identified the given name +// must exist in the token. Only the existence of the claim is checked: +// the actual value associated with that field is not checked. +func WithRequiredClaim(name string) ValidateOption { + return WithValidator(IsRequired(name)) +} + +// WithMaxDelta specifies that given two claims `c1` and `c2` that represent time, the difference in +// time.Duration must be less than equal to the value specified by `d`. If `c1` or `c2` is the +// empty string, the current time (as computed by `time.Now` or the object passed via +// `WithClock()`) is used for the comparison. +// +// `c1` and `c2` are also assumed to be required, therefore not providing either claim in the +// token will result in an error. +// +// Because there is no way of reliably knowing how to parse private claims, we currently only +// support `iat`, `exp`, and `nbf` claims. +// +// If the empty string is passed to c1 or c2, then the current time (as calculated by time.Now() or +// the clock object provided via WithClock()) is used. +// +// For example, in order to specify that `exp` - `iat` should be less than 10*time.Second, you would write +// +// jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) +// +// If AcceptableSkew of 2 second is specified, the above will return valid for any value of +// `exp` - `iat` between 8 (10-2) and 12 (10+2). +func WithMaxDelta(dur time.Duration, c1, c2 string) ValidateOption { + return WithValidator(MaxDeltaIs(c1, c2, dur)) +} + +// WithMinDelta is almost exactly the same as WithMaxDelta, but force validation to fail if +// the difference between time claims are less than dur. +// +// For example, in order to specify that `exp` - `iat` should be greater than 10*time.Second, you would write +// +// jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) +// +// The validation would fail if the difference is less than 10 seconds. +func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption { + return WithValidator(MinDeltaIs(c1, c2, dur)) +} + +// WithVerifyAuto specifies that the JWS verification should be attempted +// by using the data available in the JWS message. Currently only verification +// method available is to use the keys available in the JWKS URL pointed +// in the `jku` field. +// +// Please read the documentation for `jws.VerifyAuto` for more details. +func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) ParseOption { + return &parseOption{option.New(identVerifyAuto{}, jws.WithVerifyAuto(f, options...))} +} + +func WithInsecureNoSignature() SignOption { + return &signEncryptParseOption{option.New(identInsecureNoSignature{}, (any)(nil))} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.yaml b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.yaml new file mode 100644 index 0000000000..bfcadfac25 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options.yaml @@ -0,0 +1,274 @@ +package_name: jwt +output: jwt/options_gen.go +interfaces: + - name: GlobalOption + comment: | + GlobalOption describes an Option that can be passed to `Settings()`. + - name: EncryptOption + comment: | + EncryptOption describes an Option that can be passed to (jwt.Serializer).Encrypt + - name: ParseOption + methods: + - parseOption + - readFileOption + comment: | + ParseOption describes an Option that can be passed to `jwt.Parse()`. + ParseOption also implements ReadFileOption, therefore it may be + safely pass them to `jwt.ReadFile()` + - name: SignOption + comment: | + SignOption describes an Option that can be passed to `jwt.Sign()` or + (jwt.Serializer).Sign + - name: SignParseOption + methods: + - signOption + - parseOption + - readFileOption + comment: | + SignParseOption describes an Option that can be passed to both `jwt.Sign()` or + `jwt.Parse()` + - name: SignEncryptParseOption + methods: + - parseOption + - encryptOption + - readFileOption + - signOption + comment: | + SignEncryptParseOption describes an Option that can be passed to both `jwt.Sign()` or + `jwt.Parse()` + - name: ValidateOption + methods: + - parseOption + - readFileOption + - validateOption + comment: | + ValidateOption describes an Option that can be passed to Validate(). + ValidateOption also implements ParseOption, therefore it may be + safely passed to `Parse()` (and thus `jwt.ReadFile()`) + - name: ReadFileOption + comment: | + ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` + - name: GlobalValidateOption + methods: + - globalOption + - parseOption + - readFileOption + - validateOption + comment: | + GlobalValidateOption describes an Option that can be passed to `jwt.Settings()` and `jwt.Validate()` +options: + - ident: AcceptableSkew + interface: ValidateOption + argument_type: time.Duration + comment: | + WithAcceptableSkew specifies the duration in which exp, iat and nbf + claims may differ by. This value should be positive + - ident: Truncation + interface: GlobalValidateOption + argument_type: time.Duration + comment: | + WithTruncation specifies the amount that should be used when + truncating time values used during time-based validation routines, + and by default this is disabled. + + In v2 of this library, time values were truncated down to second accuracy, i.e. + 1.0000001 seconds is truncated to 1 second. To restore this behavior, set + this value to `time.Second` + + Since v3, this option can be passed to `jwt.Settings()` to set the truncation + value globally, as well as per invocation of `jwt.Validate()` + - ident: Clock + interface: ValidateOption + argument_type: Clock + comment: | + WithClock specifies the `Clock` to be used when verifying + exp, iat and nbf claims. + - ident: Context + interface: ValidateOption + argument_type: context.Context + comment: | + WithContext allows you to specify a context.Context object to be used + with `jwt.Validate()` option. + + Please be aware that in the next major release of this library, + `jwt.Validate()`'s signature will change to include an explicit + `context.Context` object. + - ident: ResetValidators + interface: ValidateOption + argument_type: bool + comment: | + WithResetValidators specifies that the default validators should be + reset before applying the custom validators. By default `jwt.Validate()` + checks for the validity of JWT by checking `exp`, `nbf`, and `iat`, even + when you specify more validators through other options. + + You SHOULD NOT use this option unless you know exactly what you are doing, + as this will pose significant security issues when used incorrectly. + + Using this option with the value `true` will remove all default checks, + and will expect you to specify validators as options. This is useful when you + want to skip the default validators and only use specific validators, such as + for https://openid.net/specs/openid-connect-rpinitiated-1_0.html, where + the token could be accepted even if the token is expired. + + If you set this option to true and you do not specify any validators, + `jwt.Validate()` will return an error. + + The default value is `false` (`iat`, `exp`, and `nbf` are automatically checked). + - ident: FlattenAudience + interface: GlobalOption + argument_type: bool + comment: | + WithFlattenAudience specifies the the `jwt.FlattenAudience` option on + every token defaults to enabled. You can still disable this on a per-object + basis using the `jwt.Options().Disable(jwt.FlattenAudience)` method call. + + See the documentation for `jwt.TokenOptionSet`, `(jwt.Token).Options`, and + `jwt.FlattenAudience` for more details + - ident: FormKey + interface: ParseOption + argument_type: string + comment: | + WithFormKey is used to specify header keys to search for tokens. + + While the type system allows this option to be passed to jwt.Parse() directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: HeaderKey + interface: ParseOption + argument_type: string + comment: | + WithHeaderKey is used to specify header keys to search for tokens. + + While the type system allows this option to be passed to `jwt.Parse()` directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: Cookie + interface: ParseOption + argument_type: '**http.Cookie' + comment: | + WithCookie is used to specify a variable to store the cookie used when `jwt.ParseCookie()` + is called. This allows you to inspect the cookie for additional information after a successful + parsing of the JWT token stored in the cookie. + + While the type system allows this option to be passed to `jwt.Parse()` directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: CookieKey + interface: ParseOption + argument_type: string + comment: | + WithCookieKey is used to specify cookie keys to search for tokens. + + While the type system allows this option to be passed to `jwt.Parse()` directly, + doing so will have no effect. Only use it for HTTP request parsing functions + - ident: Token + interface: ParseOption + argument_type: Token + comment: | + WithToken specifies the token instance in which the resulting JWT is stored + when parsing JWT tokens + - ident: Validate + interface: ParseOption + argument_type: bool + comment: | + WithValidate is passed to `Parse()` method to denote that the + validation of the JWT token should be performed (or not) after + a successful parsing of the incoming payload. + + This option is enabled by default. + + If you would like disable validation, + you must use `jwt.WithValidate(false)` or use `jwt.ParseInsecure()` + - ident: Verify + interface: ParseOption + argument_type: bool + comment: | + WithVerify is passed to `Parse()` method to denote that the + signature verification should be performed after a successful + deserialization of the incoming payload. + + This option is enabled by default. + + If you do not provide any verification key sources, `jwt.Parse()` + would return an error. + + If you would like to only parse the JWT payload and not verify it, + you must use `jwt.WithVerify(false)` or use `jwt.ParseInsecure()` + - ident: KeyProvider + interface: ParseOption + argument_type: jws.KeyProvider + comment: | + WithKeyProvider allows users to specify an object to provide keys to + sign/verify tokens using arbitrary code. Please read the documentation + for `jws.KeyProvider` in the `jws` package for details on how this works. + - ident: Pedantic + interface: ParseOption + argument_type: bool + comment: | + WithPedantic enables pedantic mode for parsing JWTs. Currently this only + applies to checking for the correct `typ` and/or `cty` when necessary. + - ident: EncryptOption + interface: EncryptOption + argument_type: jwe.EncryptOption + comment: | + WithEncryptOption provides an escape hatch for cases where extra options to + `(jws.Serializer).Encrypt()` must be specified when using `jwt.Sign()`. Normally you do not + need to use this. + - ident: SignOption + interface: SignOption + argument_type: jws.SignOption + comment: | + WithSignOption provides an escape hatch for cases where extra options to + `jws.Sign()` must be specified when using `jwt.Sign()`. Normally you do not + need to use this. + - ident: Validator + interface: ValidateOption + argument_type: Validator + comment: | + WithValidator validates the token with the given Validator. + + For example, in order to validate tokens that are only valid during August, you would write + + validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { + if time.Now().Month() != 8 { + return fmt.Errorf(`tokens are only valid during August!`) + } + return nil + }) + err := jwt.Validate(token, jwt.WithValidator(validator)) + - ident: FS + interface: ReadFileOption + argument_type: fs.FS + comment: | + WithFS specifies the source `fs.FS` object to read the file from. + - ident: NumericDateParsePrecision + interface: GlobalOption + argument_type: int + comment: | + WithNumericDateParsePrecision sets the precision up to which the + library uses to parse fractional dates found in the numeric date + fields. Default is 0 (second, no fractions), max is 9 (nanosecond) + - ident: NumericDateFormatPrecision + interface: GlobalOption + argument_type: int + comment: | + WithNumericDateFormatPrecision sets the precision up to which the + library uses to format fractional dates found in the numeric date + fields. Default is 0 (second, no fractions), max is 9 (nanosecond) + - ident: NumericDateParsePedantic + interface: GlobalOption + argument_type: bool + comment: | + WithNumericDateParsePedantic specifies if the parser should behave + in a pedantic manner when parsing numeric dates. Normally this library + attempts to interpret timestamps as a numeric value representing + number of seconds (with an optional fractional part), but if that fails + it tries to parse using a RFC3339 parser. This allows us to parse + payloads from non-conforming servers. + + However, when you set WithNumericDateParePedantic to `true`, the + RFC3339 parser is not tried, and we expect a numeric value strictly + - ident: Base64Encoder + interface: SignParseOption + argument_type: jws.Base64Encoder + comment: | + WithBase64Encoder specifies the base64 encoder to use for signing + tokens and verifying JWS signatures. \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options_gen.go new file mode 100644 index 0000000000..3a644a6e4c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/options_gen.go @@ -0,0 +1,495 @@ +// Code generated by tools/cmd/genoptions/main.go. DO NOT EDIT. + +package jwt + +import ( + "context" + "io/fs" + "net/http" + "time" + + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/option/v2" +) + +type Option = option.Interface + +// EncryptOption describes an Option that can be passed to (jwt.Serializer).Encrypt +type EncryptOption interface { + Option + encryptOption() +} + +type encryptOption struct { + Option +} + +func (*encryptOption) encryptOption() {} + +// GlobalOption describes an Option that can be passed to `Settings()`. +type GlobalOption interface { + Option + globalOption() +} + +type globalOption struct { + Option +} + +func (*globalOption) globalOption() {} + +// GlobalValidateOption describes an Option that can be passed to `jwt.Settings()` and `jwt.Validate()` +type GlobalValidateOption interface { + Option + globalOption() + parseOption() + readFileOption() + validateOption() +} + +type globalValidateOption struct { + Option +} + +func (*globalValidateOption) globalOption() {} + +func (*globalValidateOption) parseOption() {} + +func (*globalValidateOption) readFileOption() {} + +func (*globalValidateOption) validateOption() {} + +// ParseOption describes an Option that can be passed to `jwt.Parse()`. +// ParseOption also implements ReadFileOption, therefore it may be +// safely pass them to `jwt.ReadFile()` +type ParseOption interface { + Option + parseOption() + readFileOption() +} + +type parseOption struct { + Option +} + +func (*parseOption) parseOption() {} + +func (*parseOption) readFileOption() {} + +// ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile` +type ReadFileOption interface { + Option + readFileOption() +} + +type readFileOption struct { + Option +} + +func (*readFileOption) readFileOption() {} + +// SignEncryptParseOption describes an Option that can be passed to both `jwt.Sign()` or +// `jwt.Parse()` +type SignEncryptParseOption interface { + Option + parseOption() + encryptOption() + readFileOption() + signOption() +} + +type signEncryptParseOption struct { + Option +} + +func (*signEncryptParseOption) parseOption() {} + +func (*signEncryptParseOption) encryptOption() {} + +func (*signEncryptParseOption) readFileOption() {} + +func (*signEncryptParseOption) signOption() {} + +// SignOption describes an Option that can be passed to `jwt.Sign()` or +// (jwt.Serializer).Sign +type SignOption interface { + Option + signOption() +} + +type signOption struct { + Option +} + +func (*signOption) signOption() {} + +// SignParseOption describes an Option that can be passed to both `jwt.Sign()` or +// `jwt.Parse()` +type SignParseOption interface { + Option + signOption() + parseOption() + readFileOption() +} + +type signParseOption struct { + Option +} + +func (*signParseOption) signOption() {} + +func (*signParseOption) parseOption() {} + +func (*signParseOption) readFileOption() {} + +// ValidateOption describes an Option that can be passed to Validate(). +// ValidateOption also implements ParseOption, therefore it may be +// safely passed to `Parse()` (and thus `jwt.ReadFile()`) +type ValidateOption interface { + Option + parseOption() + readFileOption() + validateOption() +} + +type validateOption struct { + Option +} + +func (*validateOption) parseOption() {} + +func (*validateOption) readFileOption() {} + +func (*validateOption) validateOption() {} + +type identAcceptableSkew struct{} +type identBase64Encoder struct{} +type identClock struct{} +type identContext struct{} +type identCookie struct{} +type identCookieKey struct{} +type identEncryptOption struct{} +type identFS struct{} +type identFlattenAudience struct{} +type identFormKey struct{} +type identHeaderKey struct{} +type identKeyProvider struct{} +type identNumericDateFormatPrecision struct{} +type identNumericDateParsePedantic struct{} +type identNumericDateParsePrecision struct{} +type identPedantic struct{} +type identResetValidators struct{} +type identSignOption struct{} +type identToken struct{} +type identTruncation struct{} +type identValidate struct{} +type identValidator struct{} +type identVerify struct{} + +func (identAcceptableSkew) String() string { + return "WithAcceptableSkew" +} + +func (identBase64Encoder) String() string { + return "WithBase64Encoder" +} + +func (identClock) String() string { + return "WithClock" +} + +func (identContext) String() string { + return "WithContext" +} + +func (identCookie) String() string { + return "WithCookie" +} + +func (identCookieKey) String() string { + return "WithCookieKey" +} + +func (identEncryptOption) String() string { + return "WithEncryptOption" +} + +func (identFS) String() string { + return "WithFS" +} + +func (identFlattenAudience) String() string { + return "WithFlattenAudience" +} + +func (identFormKey) String() string { + return "WithFormKey" +} + +func (identHeaderKey) String() string { + return "WithHeaderKey" +} + +func (identKeyProvider) String() string { + return "WithKeyProvider" +} + +func (identNumericDateFormatPrecision) String() string { + return "WithNumericDateFormatPrecision" +} + +func (identNumericDateParsePedantic) String() string { + return "WithNumericDateParsePedantic" +} + +func (identNumericDateParsePrecision) String() string { + return "WithNumericDateParsePrecision" +} + +func (identPedantic) String() string { + return "WithPedantic" +} + +func (identResetValidators) String() string { + return "WithResetValidators" +} + +func (identSignOption) String() string { + return "WithSignOption" +} + +func (identToken) String() string { + return "WithToken" +} + +func (identTruncation) String() string { + return "WithTruncation" +} + +func (identValidate) String() string { + return "WithValidate" +} + +func (identValidator) String() string { + return "WithValidator" +} + +func (identVerify) String() string { + return "WithVerify" +} + +// WithAcceptableSkew specifies the duration in which exp, iat and nbf +// claims may differ by. This value should be positive +func WithAcceptableSkew(v time.Duration) ValidateOption { + return &validateOption{option.New(identAcceptableSkew{}, v)} +} + +// WithBase64Encoder specifies the base64 encoder to use for signing +// tokens and verifying JWS signatures. +func WithBase64Encoder(v jws.Base64Encoder) SignParseOption { + return &signParseOption{option.New(identBase64Encoder{}, v)} +} + +// WithClock specifies the `Clock` to be used when verifying +// exp, iat and nbf claims. +func WithClock(v Clock) ValidateOption { + return &validateOption{option.New(identClock{}, v)} +} + +// WithContext allows you to specify a context.Context object to be used +// with `jwt.Validate()` option. +// +// Please be aware that in the next major release of this library, +// `jwt.Validate()`'s signature will change to include an explicit +// `context.Context` object. +func WithContext(v context.Context) ValidateOption { + return &validateOption{option.New(identContext{}, v)} +} + +// WithCookie is used to specify a variable to store the cookie used when `jwt.ParseCookie()` +// is called. This allows you to inspect the cookie for additional information after a successful +// parsing of the JWT token stored in the cookie. +// +// While the type system allows this option to be passed to `jwt.Parse()` directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithCookie(v **http.Cookie) ParseOption { + return &parseOption{option.New(identCookie{}, v)} +} + +// WithCookieKey is used to specify cookie keys to search for tokens. +// +// While the type system allows this option to be passed to `jwt.Parse()` directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithCookieKey(v string) ParseOption { + return &parseOption{option.New(identCookieKey{}, v)} +} + +// WithEncryptOption provides an escape hatch for cases where extra options to +// `(jws.Serializer).Encrypt()` must be specified when using `jwt.Sign()`. Normally you do not +// need to use this. +func WithEncryptOption(v jwe.EncryptOption) EncryptOption { + return &encryptOption{option.New(identEncryptOption{}, v)} +} + +// WithFS specifies the source `fs.FS` object to read the file from. +func WithFS(v fs.FS) ReadFileOption { + return &readFileOption{option.New(identFS{}, v)} +} + +// WithFlattenAudience specifies the the `jwt.FlattenAudience` option on +// every token defaults to enabled. You can still disable this on a per-object +// basis using the `jwt.Options().Disable(jwt.FlattenAudience)` method call. +// +// See the documentation for `jwt.TokenOptionSet`, `(jwt.Token).Options`, and +// `jwt.FlattenAudience` for more details +func WithFlattenAudience(v bool) GlobalOption { + return &globalOption{option.New(identFlattenAudience{}, v)} +} + +// WithFormKey is used to specify header keys to search for tokens. +// +// While the type system allows this option to be passed to jwt.Parse() directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithFormKey(v string) ParseOption { + return &parseOption{option.New(identFormKey{}, v)} +} + +// WithHeaderKey is used to specify header keys to search for tokens. +// +// While the type system allows this option to be passed to `jwt.Parse()` directly, +// doing so will have no effect. Only use it for HTTP request parsing functions +func WithHeaderKey(v string) ParseOption { + return &parseOption{option.New(identHeaderKey{}, v)} +} + +// WithKeyProvider allows users to specify an object to provide keys to +// sign/verify tokens using arbitrary code. Please read the documentation +// for `jws.KeyProvider` in the `jws` package for details on how this works. +func WithKeyProvider(v jws.KeyProvider) ParseOption { + return &parseOption{option.New(identKeyProvider{}, v)} +} + +// WithNumericDateFormatPrecision sets the precision up to which the +// library uses to format fractional dates found in the numeric date +// fields. Default is 0 (second, no fractions), max is 9 (nanosecond) +func WithNumericDateFormatPrecision(v int) GlobalOption { + return &globalOption{option.New(identNumericDateFormatPrecision{}, v)} +} + +// WithNumericDateParsePedantic specifies if the parser should behave +// in a pedantic manner when parsing numeric dates. Normally this library +// attempts to interpret timestamps as a numeric value representing +// number of seconds (with an optional fractional part), but if that fails +// it tries to parse using a RFC3339 parser. This allows us to parse +// payloads from non-conforming servers. +// +// However, when you set WithNumericDateParePedantic to `true`, the +// RFC3339 parser is not tried, and we expect a numeric value strictly +func WithNumericDateParsePedantic(v bool) GlobalOption { + return &globalOption{option.New(identNumericDateParsePedantic{}, v)} +} + +// WithNumericDateParsePrecision sets the precision up to which the +// library uses to parse fractional dates found in the numeric date +// fields. Default is 0 (second, no fractions), max is 9 (nanosecond) +func WithNumericDateParsePrecision(v int) GlobalOption { + return &globalOption{option.New(identNumericDateParsePrecision{}, v)} +} + +// WithPedantic enables pedantic mode for parsing JWTs. Currently this only +// applies to checking for the correct `typ` and/or `cty` when necessary. +func WithPedantic(v bool) ParseOption { + return &parseOption{option.New(identPedantic{}, v)} +} + +// WithResetValidators specifies that the default validators should be +// reset before applying the custom validators. By default `jwt.Validate()` +// checks for the validity of JWT by checking `exp`, `nbf`, and `iat`, even +// when you specify more validators through other options. +// +// You SHOULD NOT use this option unless you know exactly what you are doing, +// as this will pose significant security issues when used incorrectly. +// +// Using this option with the value `true` will remove all default checks, +// and will expect you to specify validators as options. This is useful when you +// want to skip the default validators and only use specific validators, such as +// for https://openid.net/specs/openid-connect-rpinitiated-1_0.html, where +// the token could be accepted even if the token is expired. +// +// If you set this option to true and you do not specify any validators, +// `jwt.Validate()` will return an error. +// +// The default value is `false` (`iat`, `exp`, and `nbf` are automatically checked). +func WithResetValidators(v bool) ValidateOption { + return &validateOption{option.New(identResetValidators{}, v)} +} + +// WithSignOption provides an escape hatch for cases where extra options to +// `jws.Sign()` must be specified when using `jwt.Sign()`. Normally you do not +// need to use this. +func WithSignOption(v jws.SignOption) SignOption { + return &signOption{option.New(identSignOption{}, v)} +} + +// WithToken specifies the token instance in which the resulting JWT is stored +// when parsing JWT tokens +func WithToken(v Token) ParseOption { + return &parseOption{option.New(identToken{}, v)} +} + +// WithTruncation specifies the amount that should be used when +// truncating time values used during time-based validation routines, +// and by default this is disabled. +// +// In v2 of this library, time values were truncated down to second accuracy, i.e. +// 1.0000001 seconds is truncated to 1 second. To restore this behavior, set +// this value to `time.Second` +// +// Since v3, this option can be passed to `jwt.Settings()` to set the truncation +// value globally, as well as per invocation of `jwt.Validate()` +func WithTruncation(v time.Duration) GlobalValidateOption { + return &globalValidateOption{option.New(identTruncation{}, v)} +} + +// WithValidate is passed to `Parse()` method to denote that the +// validation of the JWT token should be performed (or not) after +// a successful parsing of the incoming payload. +// +// This option is enabled by default. +// +// If you would like disable validation, +// you must use `jwt.WithValidate(false)` or use `jwt.ParseInsecure()` +func WithValidate(v bool) ParseOption { + return &parseOption{option.New(identValidate{}, v)} +} + +// WithValidator validates the token with the given Validator. +// +// For example, in order to validate tokens that are only valid during August, you would write +// +// validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { +// if time.Now().Month() != 8 { +// return fmt.Errorf(`tokens are only valid during August!`) +// } +// return nil +// }) +// err := jwt.Validate(token, jwt.WithValidator(validator)) +func WithValidator(v Validator) ValidateOption { + return &validateOption{option.New(identValidator{}, v)} +} + +// WithVerify is passed to `Parse()` method to denote that the +// signature verification should be performed after a successful +// deserialization of the incoming payload. +// +// This option is enabled by default. +// +// If you do not provide any verification key sources, `jwt.Parse()` +// would return an error. +// +// If you would like to only parse the JWT payload and not verify it, +// you must use `jwt.WithVerify(false)` or use `jwt.ParseInsecure()` +func WithVerify(v bool) ParseOption { + return &parseOption{option.New(identVerify{}, v)} +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/serialize.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/serialize.go new file mode 100644 index 0000000000..9d3bdac94a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/serialize.go @@ -0,0 +1,264 @@ +package jwt + +import ( + "fmt" + + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/jwe" + "github.com/lestrrat-go/jwx/v3/jws" +) + +type SerializeCtx interface { + Step() int + Nested() bool +} + +type serializeCtx struct { + step int + nested bool +} + +func (ctx *serializeCtx) Step() int { + return ctx.step +} + +func (ctx *serializeCtx) Nested() bool { + return ctx.nested +} + +type SerializeStep interface { + Serialize(SerializeCtx, any) (any, error) +} + +// errStep is always an error. used to indicate that a method like +// serializer.Sign or Encrypt already errored out on configuration +type errStep struct { + err error +} + +func (e errStep) Serialize(_ SerializeCtx, _ any) (any, error) { + return nil, e.err +} + +// Serializer is a generic serializer for JWTs. Whereas other convenience +// functions can only do one thing (such as generate a JWS signed JWT), +// Using this construct you can serialize the token however you want. +// +// By default, the serializer only marshals the token into a JSON payload. +// You must set up the rest of the steps that should be taken by the +// serializer. +// +// For example, to marshal the token into JSON, then apply JWS and JWE +// in that order, you would do: +// +// serialized, err := jwt.NewSerializer(). +// Sign(jwa.RS256, key). +// Encrypt(jwe.WithEncryptOption(jwe.WithKey(jwa.RSA_OAEP(), publicKey))). +// Serialize(token) +// +// The `jwt.Sign()` function is equivalent to +// +// serialized, err := jwt.NewSerializer(). +// Sign(...args...). +// Serialize(token) +type Serializer struct { + steps []SerializeStep +} + +// NewSerializer creates a new empty serializer. +func NewSerializer() *Serializer { + return &Serializer{} +} + +// Reset clears all of the registered steps. +func (s *Serializer) Reset() *Serializer { + s.steps = nil + return s +} + +// Step adds a new Step to the serialization process +func (s *Serializer) Step(step SerializeStep) *Serializer { + s.steps = append(s.steps, step) + return s +} + +type jsonSerializer struct{} + +func (jsonSerializer) Serialize(_ SerializeCtx, v any) (any, error) { + token, ok := v.(Token) + if !ok { + return nil, fmt.Errorf(`invalid input: expected jwt.Token`) + } + + buf, err := json.Marshal(token) + if err != nil { + return nil, fmt.Errorf(`failed to serialize as JSON: %w`, err) + } + return buf, nil +} + +type genericHeader interface { + Get(string, any) error + Set(string, any) error + Has(string) bool +} + +func setTypeOrCty(ctx SerializeCtx, hdrs genericHeader) error { + // cty and typ are common between JWE/JWS, so we don't use + // the constants in jws/jwe package here + const typKey = `typ` + const ctyKey = `cty` + + if ctx.Step() == 1 { + // We are executed immediately after json marshaling + if !hdrs.Has(typKey) { + if err := hdrs.Set(typKey, `JWT`); err != nil { + return fmt.Errorf(`failed to set %s key to "JWT": %w`, typKey, err) + } + } + } else { + if ctx.Nested() { + // If this is part of a nested sequence, we should set cty = 'JWT' + // https://datatracker.ietf.org/doc/html/rfc7519#section-5.2 + if err := hdrs.Set(ctyKey, `JWT`); err != nil { + return fmt.Errorf(`failed to set %s key to "JWT": %w`, ctyKey, err) + } + } + } + return nil +} + +type jwsSerializer struct { + options []jws.SignOption +} + +func (s *jwsSerializer) Serialize(ctx SerializeCtx, v any) (any, error) { + payload, ok := v.([]byte) + if !ok { + return nil, fmt.Errorf(`expected []byte as input`) + } + + for _, option := range s.options { + var pc interface{ Protected(jws.Headers) jws.Headers } + if err := option.Value(&pc); err != nil { + continue + } + hdrs := pc.Protected(jws.NewHeaders()) + if err := setTypeOrCty(ctx, hdrs); err != nil { + return nil, err // this is already wrapped + } + + // JWTs MUST NOT use b64 = false + // https://datatracker.ietf.org/doc/html/rfc7797#section-7 + var b64 bool + if err := hdrs.Get("b64", &b64); err == nil { + if !b64 { // b64 = false + return nil, fmt.Errorf(`b64 cannot be false for JWTs`) + } + } + } + return jws.Sign(payload, s.options...) +} + +func (s *Serializer) Sign(options ...SignOption) *Serializer { + var soptions []jws.SignOption + if l := len(options); l > 0 { + // we need to from SignOption to Option because ... reasons + // (todo: when go1.18 prevails, use type parameters + rawoptions := make([]Option, l) + for i, option := range options { + rawoptions[i] = option + } + + converted, err := toSignOptions(rawoptions...) + if err != nil { + return s.Step(errStep{fmt.Errorf(`(jwt.Serializer).Sign: failed to convert options into jws.SignOption: %w`, err)}) + } + soptions = converted + } + return s.sign(soptions...) +} + +func (s *Serializer) sign(options ...jws.SignOption) *Serializer { + return s.Step(&jwsSerializer{ + options: options, + }) +} + +type jweSerializer struct { + options []jwe.EncryptOption +} + +func (s *jweSerializer) Serialize(ctx SerializeCtx, v any) (any, error) { + payload, ok := v.([]byte) + if !ok { + return nil, fmt.Errorf(`expected []byte as input`) + } + + hdrs := jwe.NewHeaders() + if err := setTypeOrCty(ctx, hdrs); err != nil { + return nil, err // this is already wrapped + } + + options := append([]jwe.EncryptOption{jwe.WithMergeProtectedHeaders(true), jwe.WithProtectedHeaders(hdrs)}, s.options...) + return jwe.Encrypt(payload, options...) +} + +// Encrypt specifies the JWT to be serialized as an encrypted payload. +// +// One notable difference between this method and `jwe.Encrypt()` is that +// while `jwe.Encrypt()` OVERWRITES the previous headers when `jwe.WithProtectedHeaders()` +// is provided, this method MERGES them. This is due to the fact that we +// MUST add some extra headers to construct a proper JWE message. +// Be careful when you pass multiple `jwe.EncryptOption`s. +func (s *Serializer) Encrypt(options ...EncryptOption) *Serializer { + var eoptions []jwe.EncryptOption + if l := len(options); l > 0 { + // we need to from SignOption to Option because ... reasons + // (todo: when go1.18 prevails, use type parameters + rawoptions := make([]Option, l) + for i, option := range options { + rawoptions[i] = option + } + + converted, err := toEncryptOptions(rawoptions...) + if err != nil { + return s.Step(errStep{fmt.Errorf(`(jwt.Serializer).Encrypt: failed to convert options into jwe.EncryptOption: %w`, err)}) + } + eoptions = converted + } + return s.encrypt(eoptions...) +} + +func (s *Serializer) encrypt(options ...jwe.EncryptOption) *Serializer { + return s.Step(&jweSerializer{ + options: options, + }) +} + +func (s *Serializer) Serialize(t Token) ([]byte, error) { + steps := make([]SerializeStep, len(s.steps)+1) + steps[0] = jsonSerializer{} + for i, step := range s.steps { + steps[i+1] = step + } + + var ctx serializeCtx + ctx.nested = len(s.steps) > 1 + var payload any = t + for i, step := range steps { + ctx.step = i + v, err := step.Serialize(&ctx, payload) + if err != nil { + return nil, fmt.Errorf(`failed to serialize token at step #%d: %w`, i+1, err) + } + payload = v + } + + res, ok := payload.([]byte) + if !ok { + return nil, fmt.Errorf(`invalid serialization produced`) + } + + return res, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_gen.go new file mode 100644 index 0000000000..2361ff5621 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_gen.go @@ -0,0 +1,635 @@ +// Code generated by tools/cmd/genjwt/main.go. DO NOT EDIT. + +package jwt + +import ( + "bytes" + "fmt" + "sort" + "sync" + "time" + + "github.com/lestrrat-go/blackmagic" + "github.com/lestrrat-go/jwx/v3/internal/json" + "github.com/lestrrat-go/jwx/v3/internal/pool" + "github.com/lestrrat-go/jwx/v3/internal/tokens" + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" + "github.com/lestrrat-go/jwx/v3/jwt/internal/types" +) + +const ( + AudienceKey = "aud" + ExpirationKey = "exp" + IssuedAtKey = "iat" + IssuerKey = "iss" + JwtIDKey = "jti" + NotBeforeKey = "nbf" + SubjectKey = "sub" +) + +// stdClaimNames is a list of all standard claim names defined in the JWT specification. +var stdClaimNames = []string{AudienceKey, ExpirationKey, IssuedAtKey, IssuerKey, JwtIDKey, NotBeforeKey, SubjectKey} + +// Token represents a generic JWT token. +// which are type-aware (to an extent). Other claims may be accessed via the `Get`/`Set` +// methods but their types are not taken into consideration at all. If you have non-standard +// claims that you must frequently access, consider creating accessors functions +// like the following +// +// func SetFoo(tok jwt.Token) error +// func GetFoo(tok jwt.Token) (*Customtyp, error) +// +// Embedding jwt.Token into another struct is not recommended, because +// jwt.Token needs to handle private claims, and this really does not +// work well when it is embedded in other structure +type Token interface { + // Audience returns the value for "aud" field of the token + Audience() ([]string, bool) + + // Expiration returns the value for "exp" field of the token + Expiration() (time.Time, bool) + + // IssuedAt returns the value for "iat" field of the token + IssuedAt() (time.Time, bool) + + // Issuer returns the value for "iss" field of the token + Issuer() (string, bool) + + // JwtID returns the value for "jti" field of the token + JwtID() (string, bool) + + // NotBefore returns the value for "nbf" field of the token + NotBefore() (time.Time, bool) + + // Subject returns the value for "sub" field of the token + Subject() (string, bool) + + // Get is used to extract the value of any claim, including non-standard claims, out of the token. + // + // The first argument is the name of the claim. The second argument is a pointer + // to a variable that will receive the value of the claim. The method returns + // an error if the claim does not exist, or if the value cannot be assigned to + // the destination variable. Note that a field is considered to "exist" even if + // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. + // + // For standard claims, you can use the corresponding getter method, such as + // `Issuer()`, `Subject()`, `Audience()`, `IssuedAt()`, `NotBefore()`, `ExpiresAt()` + // + // Note that fields of JWS/JWE are NOT accessible through this method. You need + // to use `jws.Parse` and `jwe.Parse` to obtain the JWS/JWE message (and NOT + // the payload, which presumably is the JWT), and then use their `Get` methods in their respective packages + Get(string, any) error + + // Set assigns a value to the corresponding field in the token. Some + // pre-defined fields such as `nbf`, `iat`, `iss` need their values to + // be of a specific type. See the other getter methods in this interface + // for the types of each of these fields + Set(string, any) error + + // Has returns true if the specified claim has a value, even if + // the value is empty-ish (e.g. 0, false, "") as long as it has been + // explicitly set. + Has(string) bool + Remove(string) error + + // Options returns the per-token options associated with this token. + // The options set value will be copied when the token is cloned via `Clone()` + // but it will not survive when the token goes through marshaling/unmarshaling + // such as `json.Marshal` and `json.Unmarshal` + Options() *TokenOptionSet + Clone() (Token, error) + Keys() []string +} +type stdToken struct { + mu *sync.RWMutex + dc DecodeCtx // per-object context for decoding + options TokenOptionSet // per-object option + audience types.StringList // https://tools.ietf.org/html/rfc7519#section-4.1.3 + expiration *types.NumericDate // https://tools.ietf.org/html/rfc7519#section-4.1.4 + issuedAt *types.NumericDate // https://tools.ietf.org/html/rfc7519#section-4.1.6 + issuer *string // https://tools.ietf.org/html/rfc7519#section-4.1.1 + jwtID *string // https://tools.ietf.org/html/rfc7519#section-4.1.7 + notBefore *types.NumericDate // https://tools.ietf.org/html/rfc7519#section-4.1.5 + subject *string // https://tools.ietf.org/html/rfc7519#section-4.1.2 + privateClaims map[string]any +} + +// New creates a standard token, with minimal knowledge of +// possible claims. Standard claims include"aud", "exp", "iat", "iss", "jti", "nbf" and "sub". +// Convenience accessors are provided for these standard claims +func New() Token { + return &stdToken{ + mu: &sync.RWMutex{}, + privateClaims: make(map[string]any), + options: DefaultOptionSet(), + } +} + +func (t *stdToken) Options() *TokenOptionSet { + return &t.options +} + +func (t *stdToken) Has(name string) bool { + t.mu.RLock() + defer t.mu.RUnlock() + switch name { + case AudienceKey: + return t.audience != nil + case ExpirationKey: + return t.expiration != nil + case IssuedAtKey: + return t.issuedAt != nil + case IssuerKey: + return t.issuer != nil + case JwtIDKey: + return t.jwtID != nil + case NotBeforeKey: + return t.notBefore != nil + case SubjectKey: + return t.subject != nil + default: + _, ok := t.privateClaims[name] + return ok + } +} + +func (t *stdToken) Get(name string, dst any) error { + t.mu.RLock() + defer t.mu.RUnlock() + switch name { + case AudienceKey: + if t.audience == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.audience.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case ExpirationKey: + if t.expiration == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.expiration.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case IssuedAtKey: + if t.issuedAt == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.issuedAt.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case IssuerKey: + if t.issuer == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, *(t.issuer)); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case JwtIDKey: + if t.jwtID == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, *(t.jwtID)); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case NotBeforeKey: + if t.notBefore == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, t.notBefore.Get()); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + case SubjectKey: + if t.subject == nil { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, *(t.subject)); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + default: + v, ok := t.privateClaims[name] + if !ok { + return jwterrs.ClaimNotFoundError{Name: name} + } + if err := blackmagic.AssignIfCompatible(dst, v); err != nil { + return jwterrs.ClaimAssignmentFailedError{Err: err} + } + return nil + } +} + +func (t *stdToken) Remove(key string) error { + t.mu.Lock() + defer t.mu.Unlock() + switch key { + case AudienceKey: + t.audience = nil + case ExpirationKey: + t.expiration = nil + case IssuedAtKey: + t.issuedAt = nil + case IssuerKey: + t.issuer = nil + case JwtIDKey: + t.jwtID = nil + case NotBeforeKey: + t.notBefore = nil + case SubjectKey: + t.subject = nil + default: + delete(t.privateClaims, key) + } + return nil +} + +func (t *stdToken) Set(name string, value any) error { + t.mu.Lock() + defer t.mu.Unlock() + return t.setNoLock(name, value) +} + +func (t *stdToken) DecodeCtx() DecodeCtx { + t.mu.RLock() + defer t.mu.RUnlock() + return t.dc +} + +func (t *stdToken) SetDecodeCtx(v DecodeCtx) { + t.mu.Lock() + defer t.mu.Unlock() + t.dc = v +} + +func (t *stdToken) setNoLock(name string, value any) error { + switch name { + case AudienceKey: + var acceptor types.StringList + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, AudienceKey, err) + } + t.audience = acceptor + return nil + case ExpirationKey: + var acceptor types.NumericDate + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, ExpirationKey, err) + } + t.expiration = &acceptor + return nil + case IssuedAtKey: + var acceptor types.NumericDate + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, IssuedAtKey, err) + } + t.issuedAt = &acceptor + return nil + case IssuerKey: + if v, ok := value.(string); ok { + t.issuer = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, IssuerKey, value) + case JwtIDKey: + if v, ok := value.(string); ok { + t.jwtID = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, JwtIDKey, value) + case NotBeforeKey: + var acceptor types.NumericDate + if err := acceptor.Accept(value); err != nil { + return fmt.Errorf(`invalid value for %s key: %w`, NotBeforeKey, err) + } + t.notBefore = &acceptor + return nil + case SubjectKey: + if v, ok := value.(string); ok { + t.subject = &v + return nil + } + return fmt.Errorf(`invalid value for %s key: %T`, SubjectKey, value) + default: + if t.privateClaims == nil { + t.privateClaims = map[string]any{} + } + t.privateClaims[name] = value + } + return nil +} + +func (t *stdToken) Audience() ([]string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.audience != nil { + return t.audience.Get(), true + } + return nil, false +} + +func (t *stdToken) Expiration() (time.Time, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.expiration != nil { + return t.expiration.Get(), true + } + return time.Time{}, false +} + +func (t *stdToken) IssuedAt() (time.Time, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.issuedAt != nil { + return t.issuedAt.Get(), true + } + return time.Time{}, false +} + +func (t *stdToken) Issuer() (string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.issuer != nil { + return *(t.issuer), true + } + return "", false +} + +func (t *stdToken) JwtID() (string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.jwtID != nil { + return *(t.jwtID), true + } + return "", false +} + +func (t *stdToken) NotBefore() (time.Time, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.notBefore != nil { + return t.notBefore.Get(), true + } + return time.Time{}, false +} + +func (t *stdToken) Subject() (string, bool) { + t.mu.RLock() + defer t.mu.RUnlock() + if t.subject != nil { + return *(t.subject), true + } + return "", false +} + +func (t *stdToken) PrivateClaims() map[string]any { + t.mu.RLock() + defer t.mu.RUnlock() + return t.privateClaims +} + +func (t *stdToken) UnmarshalJSON(buf []byte) error { + t.mu.Lock() + defer t.mu.Unlock() + t.audience = nil + t.expiration = nil + t.issuedAt = nil + t.issuer = nil + t.jwtID = nil + t.notBefore = nil + t.subject = nil + dec := json.NewDecoder(bytes.NewReader(buf)) +LOOP: + for { + tok, err := dec.Token() + if err != nil { + return fmt.Errorf(`error reading token: %w`, err) + } + switch tok := tok.(type) { + case json.Delim: + // Assuming we're doing everything correctly, we should ONLY + // get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here. + if tok == tokens.CloseCurlyBracket { // End of object + break LOOP + } else if tok != tokens.OpenCurlyBracket { + return fmt.Errorf(`expected '%c', but got '%c'`, tokens.OpenCurlyBracket, tok) + } + case string: // Objects can only have string keys + switch tok { + case AudienceKey: + var decoded types.StringList + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, AudienceKey, err) + } + t.audience = decoded + case ExpirationKey: + var decoded types.NumericDate + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, ExpirationKey, err) + } + t.expiration = &decoded + case IssuedAtKey: + var decoded types.NumericDate + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, IssuedAtKey, err) + } + t.issuedAt = &decoded + case IssuerKey: + if err := json.AssignNextStringToken(&t.issuer, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, IssuerKey, err) + } + case JwtIDKey: + if err := json.AssignNextStringToken(&t.jwtID, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, JwtIDKey, err) + } + case NotBeforeKey: + var decoded types.NumericDate + if err := dec.Decode(&decoded); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, NotBeforeKey, err) + } + t.notBefore = &decoded + case SubjectKey: + if err := json.AssignNextStringToken(&t.subject, dec); err != nil { + return fmt.Errorf(`failed to decode value for key %s: %w`, SubjectKey, err) + } + default: + if dc := t.dc; dc != nil { + if localReg := dc.Registry(); localReg != nil { + decoded, err := localReg.Decode(dec, tok) + if err == nil { + t.setNoLock(tok, decoded) + continue + } + } + } + decoded, err := registry.Decode(dec, tok) + if err == nil { + t.setNoLock(tok, decoded) + continue + } + return fmt.Errorf(`could not decode field %s: %w`, tok, err) + } + default: + return fmt.Errorf(`invalid token %T`, tok) + } + } + return nil +} + +func (t *stdToken) Keys() []string { + t.mu.RLock() + defer t.mu.RUnlock() + keys := make([]string, 0, 7+len(t.privateClaims)) + if t.audience != nil { + keys = append(keys, AudienceKey) + } + if t.expiration != nil { + keys = append(keys, ExpirationKey) + } + if t.issuedAt != nil { + keys = append(keys, IssuedAtKey) + } + if t.issuer != nil { + keys = append(keys, IssuerKey) + } + if t.jwtID != nil { + keys = append(keys, JwtIDKey) + } + if t.notBefore != nil { + keys = append(keys, NotBeforeKey) + } + if t.subject != nil { + keys = append(keys, SubjectKey) + } + for k := range t.privateClaims { + keys = append(keys, k) + } + return keys +} + +type claimPair struct { + Name string + Value any +} + +var claimPairPool = sync.Pool{ + New: func() any { + return make([]claimPair, 0, 7) + }, +} + +func getClaimPairList() []claimPair { + return claimPairPool.Get().([]claimPair) +} + +func putClaimPairList(list []claimPair) { + list = list[:0] + claimPairPool.Put(list) +} + +// makePairs creates a list of claimPair objects that are sorted by +// their key names. The key names are always their JSON names, and +// the values are already JSON encoded. +// Because makePairs needs to allocate a slice, it _slows_ down +// marshaling of the token to JSON. The upside is that it allows us to +// marshal the token keys in a deterministic order. +// Do we really need it...? Well, technically we don't, but it's so +// much nicer to have this to make the example tests actually work +// deterministically. Also if for whatever reason this becomes a +// performance issue, we can always/ add a flag to use a more _optimized_ code path. +// +// The caller is responsible to call putClaimPairList() to return the +// allocated slice back to the pool. + +func (t *stdToken) makePairs() ([]claimPair, error) { + pairs := getClaimPairList() + if t.audience != nil { + buf, err := json.MarshalAudience(t.audience, t.options.IsEnabled(FlattenAudience)) + if err != nil { + return nil, fmt.Errorf(`failed to encode "aud": %w`, err) + } + pairs = append(pairs, claimPair{Name: AudienceKey, Value: buf}) + } + if t.expiration != nil { + buf, err := json.Marshal(t.expiration.Unix()) + if err != nil { + return nil, fmt.Errorf(`failed to encode "exp": %w`, err) + } + pairs = append(pairs, claimPair{Name: ExpirationKey, Value: buf}) + } + if t.issuedAt != nil { + buf, err := json.Marshal(t.issuedAt.Unix()) + if err != nil { + return nil, fmt.Errorf(`failed to encode "iat": %w`, err) + } + pairs = append(pairs, claimPair{Name: IssuedAtKey, Value: buf}) + } + if t.issuer != nil { + buf, err := json.Marshal(*(t.issuer)) + if err != nil { + return nil, fmt.Errorf(`failed to encode field "iss": %w`, err) + } + pairs = append(pairs, claimPair{Name: IssuerKey, Value: buf}) + } + if t.jwtID != nil { + buf, err := json.Marshal(*(t.jwtID)) + if err != nil { + return nil, fmt.Errorf(`failed to encode field "jti": %w`, err) + } + pairs = append(pairs, claimPair{Name: JwtIDKey, Value: buf}) + } + if t.notBefore != nil { + buf, err := json.Marshal(t.notBefore.Unix()) + if err != nil { + return nil, fmt.Errorf(`failed to encode "nbf": %w`, err) + } + pairs = append(pairs, claimPair{Name: NotBeforeKey, Value: buf}) + } + if t.subject != nil { + buf, err := json.Marshal(*(t.subject)) + if err != nil { + return nil, fmt.Errorf(`failed to encode field "sub": %w`, err) + } + pairs = append(pairs, claimPair{Name: SubjectKey, Value: buf}) + } + for k, v := range t.privateClaims { + buf, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf(`failed to encode field %q: %w`, k, err) + } + pairs = append(pairs, claimPair{Name: k, Value: buf}) + } + + sort.Slice(pairs, func(i, j int) bool { + return pairs[i].Name < pairs[j].Name + }) + + return pairs, nil +} + +func (t stdToken) MarshalJSON() ([]byte, error) { + buf := pool.BytesBuffer().Get() + defer pool.BytesBuffer().Put(buf) + pairs, err := t.makePairs() + if err != nil { + return nil, fmt.Errorf(`failed to make pairs: %w`, err) + } + buf.WriteByte(tokens.OpenCurlyBracket) + + for i, pair := range pairs { + if i > 0 { + buf.WriteByte(tokens.Comma) + } + fmt.Fprintf(buf, "%q: %s", pair.Name, pair.Value) + } + buf.WriteByte(tokens.CloseCurlyBracket) + ret := make([]byte, buf.Len()) + copy(ret, buf.Bytes()) + putClaimPairList(pairs) + return ret, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options.go new file mode 100644 index 0000000000..0f54e05611 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options.go @@ -0,0 +1,78 @@ +package jwt + +import "sync" + +// TokenOptionSet is a bit flag containing per-token options. +type TokenOptionSet uint64 + +var defaultOptions TokenOptionSet +var defaultOptionsMu sync.RWMutex + +// TokenOption describes a single token option that can be set on +// the per-token option set (TokenOptionSet) +type TokenOption uint64 + +const ( + // FlattenAudience option controls whether the "aud" claim should be flattened + // to a single string upon the token being serialized to JSON. + // + // This is sometimes important when a JWT consumer does not understand that + // the "aud" claim can actually take the form of an array of strings. + // (We have been notified by users that AWS Cognito has manifested this behavior + // at some point) + // + // Unless the global option is set using `jwt.Settings()`, the default value is + // `disabled`, which means that "aud" claims are always rendered as a arrays of + // strings when serialized to JSON. + FlattenAudience TokenOption = 1 << iota + + // MaxPerTokenOption is a marker to denote the last value that an option can take. + // This value has no meaning other than to be used as a marker. + MaxPerTokenOption +) + +// Value returns the uint64 value of a single option +func (o TokenOption) Value() uint64 { + return uint64(o) +} + +// Value returns the uint64 bit flag value of an option set +func (o TokenOptionSet) Value() uint64 { + return uint64(o) +} + +// DefaultOptionSet creates a new TokenOptionSet using the default +// option set. This may differ depending on if/when functions that +// change the global state has been called, such as `jwt.Settings` +func DefaultOptionSet() TokenOptionSet { + return TokenOptionSet(defaultOptions.Value()) +} + +// Clear sets all bits to zero, effectively disabling all options +func (o *TokenOptionSet) Clear() { + *o = TokenOptionSet(uint64(0)) +} + +// Set sets the value of this option set, effectively *replacing* +// the entire option set with the new value. This is NOT the same +// as Enable/Disable. +func (o *TokenOptionSet) Set(s TokenOptionSet) { + *o = s +} + +// Enable sets the appropriate value to enable the option in the +// option set +func (o *TokenOptionSet) Enable(flag TokenOption) { + *o = TokenOptionSet(o.Value() | uint64(flag)) +} + +// Enable sets the appropriate value to disable the option in the +// option set +func (o *TokenOptionSet) Disable(flag TokenOption) { + *o = TokenOptionSet(o.Value() & ^uint64(flag)) +} + +// IsEnabled returns true if the given bit on the option set is enabled. +func (o TokenOptionSet) IsEnabled(flag TokenOption) bool { + return (uint64(o)&uint64(flag) == uint64(flag)) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options_gen.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options_gen.go new file mode 100644 index 0000000000..7e7cbf14aa --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/token_options_gen.go @@ -0,0 +1,25 @@ +// Code generated by "stringer -type=TokenOption -output=token_options_gen.go"; DO NOT EDIT. + +package jwt + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[FlattenAudience-1] + _ = x[MaxPerTokenOption-2] +} + +const _TokenOption_name = "FlattenAudienceMaxPerTokenOption" + +var _TokenOption_index = [...]uint8{0, 15, 32} + +func (i TokenOption) String() string { + i -= 1 + if i >= TokenOption(len(_TokenOption_index)-1) { + return "TokenOption(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _TokenOption_name[_TokenOption_index[i]:_TokenOption_index[i+1]] +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwt/validate.go b/vendor/github.com/lestrrat-go/jwx/v3/jwt/validate.go new file mode 100644 index 0000000000..dbc43edbc2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwt/validate.go @@ -0,0 +1,418 @@ +package jwt + +import ( + "context" + "fmt" + "strconv" + "time" + + jwterrs "github.com/lestrrat-go/jwx/v3/jwt/internal/errors" +) + +type Clock interface { + Now() time.Time +} +type ClockFunc func() time.Time + +func (f ClockFunc) Now() time.Time { + return f() +} + +func isSupportedTimeClaim(c string) error { + switch c { + case ExpirationKey, IssuedAtKey, NotBeforeKey: + return nil + } + return fmt.Errorf(`unsupported time claim %s`, strconv.Quote(c)) +} + +func timeClaim(t Token, clock Clock, c string) time.Time { + // We don't check if the claims already exist. It should have been done + // by piggybacking on `required` check. + switch c { + case ExpirationKey: + tv, _ := t.Expiration() + return tv + case IssuedAtKey: + tv, _ := t.IssuedAt() + return tv + case NotBeforeKey: + tv, _ := t.NotBefore() + return tv + case "": + return clock.Now() + } + return time.Time{} // should *NEVER* reach here, but... +} + +// Validate makes sure that the essential claims stand. +// +// See the various `WithXXX` functions for optional parameters +// that can control the behavior of this method. +func Validate(t Token, options ...ValidateOption) error { + ctx := context.Background() + trunc := getDefaultTruncation() + + var clock Clock = ClockFunc(time.Now) + var skew time.Duration + var baseValidators = []Validator{ + IsIssuedAtValid(), + IsExpirationValid(), + IsNbfValid(), + } + var extraValidators []Validator + var resetValidators bool + for _, o := range options { + switch o.Ident() { + case identClock{}: + if err := o.Value(&clock); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithClock() option must be jwt.Clock: %w`, err) + } + case identAcceptableSkew{}: + if err := o.Value(&skew); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithAcceptableSkew() option must be time.Duration: %w`, err) + } + case identTruncation{}: + if err := o.Value(&trunc); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithTruncation() option must be time.Duration: %w`, err) + } + case identContext{}: + if err := o.Value(&ctx); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithContext() option must be context.Context: %w`, err) + } + case identResetValidators{}: + if err := o.Value(&resetValidators); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithResetValidators() option must be bool: %w`, err) + } + case identValidator{}: + var v Validator + if err := o.Value(&v); err != nil { + return fmt.Errorf(`jwt.Validate: value for WithValidator() option must be jwt.Validator: %w`, err) + } + switch v := v.(type) { + case *isInTimeRange: + if v.c1 != "" { + if err := isSupportedTimeClaim(v.c1); err != nil { + return err + } + extraValidators = append(extraValidators, IsRequired(v.c1)) + } + if v.c2 != "" { + if err := isSupportedTimeClaim(v.c2); err != nil { + return err + } + extraValidators = append(extraValidators, IsRequired(v.c2)) + } + } + extraValidators = append(extraValidators, v) + } + } + + ctx = SetValidationCtxSkew(ctx, skew) + ctx = SetValidationCtxClock(ctx, clock) + ctx = SetValidationCtxTruncation(ctx, trunc) + + var validators []Validator + if !resetValidators { + validators = append(baseValidators, extraValidators...) + } else { + if len(extraValidators) == 0 { + return jwterrs.ValidateErrorf(`no validators specified: jwt.WithResetValidators(true) and no jwt.WithValidator() specified`) + } + validators = extraValidators + } + + for _, v := range validators { + if err := v.Validate(ctx, t); err != nil { + return jwterrs.ValidateErrorf(`validation failed: %w`, err) + } + } + + return nil +} + +type isInTimeRange struct { + c1 string + c2 string + dur time.Duration + less bool // if true, d =< c1 - c2. otherwise d >= c1 - c2 +} + +// MaxDeltaIs implements the logic behind `WithMaxDelta()` option +func MaxDeltaIs(c1, c2 string, dur time.Duration) Validator { + return &isInTimeRange{ + c1: c1, + c2: c2, + dur: dur, + less: true, + } +} + +// MinDeltaIs implements the logic behind `WithMinDelta()` option +func MinDeltaIs(c1, c2 string, dur time.Duration) Validator { + return &isInTimeRange{ + c1: c1, + c2: c2, + dur: dur, + less: false, + } +} + +func (iitr *isInTimeRange) Validate(ctx context.Context, t Token) error { + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + // We don't check if the claims already exist, because we already did that + // by piggybacking on `required` check. + t1 := timeClaim(t, clock, iitr.c1) + t2 := timeClaim(t, clock, iitr.c2) + if iitr.less { // t1 - t2 <= iitr.dur + // t1 - t2 < iitr.dur + skew + if t1.Sub(t2) > iitr.dur+skew { + return fmt.Errorf(`iitr between %s and %s exceeds %s (skew %s)`, iitr.c1, iitr.c2, iitr.dur, skew) + } + } else { + if t1.Sub(t2) < iitr.dur-skew { + return fmt.Errorf(`iitr between %s and %s is less than %s (skew %s)`, iitr.c1, iitr.c2, iitr.dur, skew) + } + } + return nil +} + +// Validator describes interface to validate a Token. +type Validator interface { + // Validate should return an error if a required conditions is not met. + Validate(context.Context, Token) error +} + +// ValidatorFunc is a type of Validator that does not have any +// state, that is implemented as a function +type ValidatorFunc func(context.Context, Token) error + +func (vf ValidatorFunc) Validate(ctx context.Context, tok Token) error { + return vf(ctx, tok) +} + +type identValidationCtxClock struct{} +type identValidationCtxSkew struct{} +type identValidationCtxTruncation struct{} + +func SetValidationCtxClock(ctx context.Context, cl Clock) context.Context { + return context.WithValue(ctx, identValidationCtxClock{}, cl) +} + +func SetValidationCtxTruncation(ctx context.Context, dur time.Duration) context.Context { + return context.WithValue(ctx, identValidationCtxTruncation{}, dur) +} + +func SetValidationCtxSkew(ctx context.Context, dur time.Duration) context.Context { + return context.WithValue(ctx, identValidationCtxSkew{}, dur) +} + +// ValidationCtxClock returns the Clock object associated with +// the current validation context. This value will always be available +// during validation of tokens. +func ValidationCtxClock(ctx context.Context) Clock { + //nolint:forcetypeassert + return ctx.Value(identValidationCtxClock{}).(Clock) +} + +func ValidationCtxSkew(ctx context.Context) time.Duration { + //nolint:forcetypeassert + return ctx.Value(identValidationCtxSkew{}).(time.Duration) +} + +func ValidationCtxTruncation(ctx context.Context) time.Duration { + //nolint:forcetypeassert + return ctx.Value(identValidationCtxTruncation{}).(time.Duration) +} + +// IsExpirationValid is one of the default validators that will be executed. +// It does not need to be specified by users, but it exists as an +// exported field so that you can check what it does. +// +// The supplied context.Context object must have the "clock" and "skew" +// populated with appropriate values using SetValidationCtxClock() and +// SetValidationCtxSkew() +func IsExpirationValid() Validator { + return ValidatorFunc(isExpirationValid) +} + +func isExpirationValid(ctx context.Context, t Token) error { + tv, ok := t.Expiration() + if !ok { + return nil + } + + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + trunc := ValidationCtxTruncation(ctx) // MUST be populated + + now := clock.Now().Truncate(trunc) + ttv := tv.Truncate(trunc) + + // expiration date must be after NOW + if !now.Before(ttv.Add(skew)) { + return TokenExpiredError() + } + return nil +} + +// IsIssuedAtValid is one of the default validators that will be executed. +// It does not need to be specified by users, but it exists as an +// exported field so that you can check what it does. +// +// The supplied context.Context object must have the "clock" and "skew" +// populated with appropriate values using SetValidationCtxClock() and +// SetValidationCtxSkew() +func IsIssuedAtValid() Validator { + return ValidatorFunc(isIssuedAtValid) +} + +func isIssuedAtValid(ctx context.Context, t Token) error { + tv, ok := t.IssuedAt() + if !ok { + return nil + } + + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + trunc := ValidationCtxTruncation(ctx) // MUST be populated + + now := clock.Now().Truncate(trunc) + ttv := tv.Truncate(trunc) + + if now.Before(ttv.Add(-1 * skew)) { + return InvalidIssuedAtError() + } + return nil +} + +// IsNbfValid is one of the default validators that will be executed. +// It does not need to be specified by users, but it exists as an +// exported field so that you can check what it does. +// +// The supplied context.Context object must have the "clock" and "skew" +// populated with appropriate values using SetValidationCtxClock() and +// SetValidationCtxSkew() +func IsNbfValid() Validator { + return ValidatorFunc(isNbfValid) +} + +func isNbfValid(ctx context.Context, t Token) error { + tv, ok := t.NotBefore() + if !ok { + return nil + } + + clock := ValidationCtxClock(ctx) // MUST be populated + skew := ValidationCtxSkew(ctx) // MUST be populated + trunc := ValidationCtxTruncation(ctx) // MUST be populated + + // Truncation always happens even for trunc = 0 because + // we also use this to strip monotonic clocks + now := clock.Now().Truncate(trunc) + ttv := tv.Truncate(trunc) + + // "now" cannot be before t - skew, so we check for now > t - skew + ttv = ttv.Add(-1 * skew) + if now.Before(ttv) { + return TokenNotYetValidError() + } + return nil +} + +type claimContainsString struct { + name string + value string + makeErr func(string, ...any) error +} + +// ClaimContainsString can be used to check if the claim called `name`, which is +// expected to be a list of strings, contains `value`. Currently, because of the +// implementation, this will probably only work for `aud` fields. +func ClaimContainsString(name, value string) Validator { + return claimContainsString{ + name: name, + value: value, + makeErr: fmt.Errorf, + } +} + +func (ccs claimContainsString) Validate(_ context.Context, t Token) error { + var list []string + if err := t.Get(ccs.name, &list); err != nil { + return ccs.makeErr(`claim %q does not exist or is not a []string: %w`, ccs.name, err) + } + + for _, v := range list { + if v == ccs.value { + return nil + } + } + return ccs.makeErr(`%q not satisfied`, ccs.name) +} + +// audienceClaimContainsString can be used to check if the audience claim, which is +// expected to be a list of strings, contains `value`. +func audienceClaimContainsString(value string) Validator { + return claimContainsString{ + name: AudienceKey, + value: value, + makeErr: jwterrs.AudienceErrorf, + } +} + +type claimValueIs struct { + name string + value any + makeErr func(string, ...any) error +} + +// ClaimValueIs creates a Validator that checks if the value of claim `name` +// matches `value`. The comparison is done using a simple `==` comparison, +// and therefore complex comparisons may fail using this code. If you +// need to do more, use a custom Validator. +func ClaimValueIs(name string, value any) Validator { + return &claimValueIs{ + name: name, + value: value, + makeErr: fmt.Errorf, + } +} + +func (cv *claimValueIs) Validate(_ context.Context, t Token) error { + var v any + if err := t.Get(cv.name, &v); err != nil { + return cv.makeErr(`claim %[1]q does not exist or is not a []string: %[2]w`, cv.name, err) + } + if v != cv.value { + return cv.makeErr(`claim %[1]q does not have the expected value`, cv.name) + } + return nil +} + +// issuerClaimValueIs creates a Validator that checks if the issuer claim +// matches `value`. +func issuerClaimValueIs(value string) Validator { + return &claimValueIs{ + name: IssuerKey, + value: value, + makeErr: jwterrs.IssuerErrorf, + } +} + +// IsRequired creates a Validator that checks if the required claim `name` +// exists in the token +func IsRequired(name string) Validator { + return isRequired(name) +} + +type isRequired string + +func (ir isRequired) Validate(_ context.Context, t Token) error { + name := string(ir) + if !t.Has(name) { + return jwterrs.MissingRequiredClaimErrorf(name) + } + return nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/jwx.go b/vendor/github.com/lestrrat-go/jwx/v3/jwx.go new file mode 100644 index 0000000000..fc394e5137 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/jwx.go @@ -0,0 +1,45 @@ +//go:generate ./tools/cmd/genreadfile.sh +//go:generate ./tools/cmd/genoptions.sh +//go:generate stringer -type=FormatKind +//go:generate mv formatkind_string.go formatkind_string_gen.go + +// Package jwx contains tools that deal with the various JWx (JOSE) +// technologies such as JWT, JWS, JWE, etc in Go. +// +// JWS (https://tools.ietf.org/html/rfc7515) +// JWE (https://tools.ietf.org/html/rfc7516) +// JWK (https://tools.ietf.org/html/rfc7517) +// JWA (https://tools.ietf.org/html/rfc7518) +// JWT (https://tools.ietf.org/html/rfc7519) +// +// Examples are stored in a separate Go module (to avoid adding +// dependencies to this module), and thus does not appear in the +// online documentation for this module. +// You can find the examples in Github at https://github.com/lestrrat-go/jwx/tree/v3/examples +// +// You can find more high level documentation at Github (https://github.com/lestrrat-go/jwx/tree/v2) +// +// FAQ style documentation can be found in the repository (https://github.com/lestrrat-go/jwx/tree/develop/v3/docs) +package jwx + +import ( + "github.com/lestrrat-go/jwx/v3/internal/json" +) + +// DecoderSettings gives you a access to configure the "encoding/json".Decoder +// used to decode JSON objects within the jwx framework. +func DecoderSettings(options ...JSONOption) { + // XXX We're using this format instead of just passing a single boolean + // in case a new option is to be added some time later + var useNumber bool + for _, option := range options { + switch option.Ident() { + case identUseNumber{}: + if err := option.Value(&useNumber); err != nil { + panic("jwx.DecoderSettings: useNumber option must be a boolean") + } + } + } + + json.DecoderSettings(useNumber) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/options.go b/vendor/github.com/lestrrat-go/jwx/v3/options.go new file mode 100644 index 0000000000..b642a199d8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/options.go @@ -0,0 +1,30 @@ +package jwx + +import "github.com/lestrrat-go/option/v2" + +type identUseNumber struct{} + +type Option = option.Interface + +type JSONOption interface { + Option + isJSONOption() +} + +type jsonOption struct { + Option +} + +func (o *jsonOption) isJSONOption() {} + +func newJSONOption(n any, v any) JSONOption { + return &jsonOption{option.New(n, v)} +} + +// WithUseNumber controls whether the jwx package should unmarshal +// JSON objects with the "encoding/json".Decoder.UseNumber feature on. +// +// Default is false. +func WithUseNumber(b bool) JSONOption { + return newJSONOption(identUseNumber{}, b) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/transform/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v3/transform/BUILD.bazel new file mode 100644 index 0000000000..3333c6607c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/transform/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "transform", + srcs = [ + "filter.go", + "map.go", + ], + importpath = "github.com/lestrrat-go/jwx/v3/transform", + visibility = ["//visibility:public"], + deps = [ + "@com_github_lestrrat_go_blackmagic//:blackmagic", + ], +) + +go_test( + name = "transform_test", + srcs = [ + "map_test.go", + ], + deps = [ + ":transform", + "//jwt", + "@com_github_stretchr_testify//require", + ], +) + +alias( + name = "go_default_library", + actual = ":transform", + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jwx/v3/transform/filter.go b/vendor/github.com/lestrrat-go/jwx/v3/transform/filter.go new file mode 100644 index 0000000000..da2972db6a --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/transform/filter.go @@ -0,0 +1,115 @@ +package transform + +import "sync" + +// FilterLogic is an interface that defines the logic for filtering objects. +type FilterLogic interface { + Apply(key string, object any) bool +} + +// FilterLogicFunc is a function type that implements the FilterLogic interface. +type FilterLogicFunc func(key string, object any) bool + +func (f FilterLogicFunc) Apply(key string, object any) bool { + return f(key, object) +} + +// Filterable is an interface that must be implemented by objects that can be filtered. +type Filterable[T any] interface { + // Keys returns the names of all fields in the object. + Keys() []string + + // Clone returns a deep copy of the object. + Clone() (T, error) + + // Remove removes a field from the object. + Remove(string) error +} + +// Apply is a standalone function that provides type-safe filtering based on +// specified filter logic. +// +// It returns a new object with only the fields that match the result of `logic.Apply`. +func Apply[T Filterable[T]](object T, logic FilterLogic) (T, error) { + return filterWith(object, logic, true) +} + +// Reject is a standalone function that provides type-safe filtering based on +// specified filter logic. +// +// It returns a new object with only the fields that DO NOT match the result +// of `logic.Apply`. +func Reject[T Filterable[T]](object T, logic FilterLogic) (T, error) { + return filterWith(object, logic, false) +} + +// filterWith is an internal function used by both Apply and Reject functions +// to apply the filtering logic to an object. If include is true, only fields +// matching the logic are included. If include is false, fields matching +// the logic are excluded. +func filterWith[T Filterable[T]](object T, logic FilterLogic, include bool) (T, error) { + var zero T + + result, err := object.Clone() + if err != nil { + return zero, err + } + + for _, k := range result.Keys() { + if ok := logic.Apply(k, object); (include && ok) || (!include && !ok) { + continue + } + + if err := result.Remove(k); err != nil { + return zero, err + } + } + + return result, nil +} + +// NameBasedFilter is a filter that filters fields based on their field names. +type NameBasedFilter[T Filterable[T]] struct { + names map[string]struct{} + mu sync.RWMutex + logic FilterLogic +} + +// NewNameBasedFilter creates a new NameBasedFilter with the specified field names. +// +// NameBasedFilter is the underlying implementation of the +// various filters in jwe, jwk, jws, and jwt packages. You normally do not +// need to use this directly. +func NewNameBasedFilter[T Filterable[T]](names ...string) *NameBasedFilter[T] { + nameMap := make(map[string]struct{}, len(names)) + for _, name := range names { + nameMap[name] = struct{}{} + } + + nf := &NameBasedFilter[T]{ + names: nameMap, + } + + nf.logic = FilterLogicFunc(nf.filter) + return nf +} + +func (nf *NameBasedFilter[T]) filter(k string, _ any) bool { + _, ok := nf.names[k] + return ok +} + +// Filter returns a new object with only the fields that match the specified names. +func (nf *NameBasedFilter[T]) Filter(object T) (T, error) { + nf.mu.RLock() + defer nf.mu.RUnlock() + + return Apply(object, nf.logic) +} + +// Reject returns a new object with only the fields that DO NOT match the specified names. +func (nf *NameBasedFilter[T]) Reject(object T) (T, error) { + nf.mu.RLock() + defer nf.mu.RUnlock() + return Reject(object, nf.logic) +} diff --git a/vendor/github.com/lestrrat-go/jwx/v3/transform/map.go b/vendor/github.com/lestrrat-go/jwx/v3/transform/map.go new file mode 100644 index 0000000000..4eb80cb99f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v3/transform/map.go @@ -0,0 +1,46 @@ +package transform + +import ( + "errors" + "fmt" + + "github.com/lestrrat-go/blackmagic" +) + +// Mappable is an interface that defines methods required when converting +// a jwx structure into a map[string]any. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +type Mappable interface { + Get(key string, dst any) error + Keys() []string +} + +// AsMap takes the specified Mappable object and populates the map +// `dst` with the key-value pairs from the Mappable object. +// Many objects in jwe, jwk, jws, and jwt packages including +// `jwt.Token`, `jwk.Key`, `jws.Header`, etc. +// +// EXPERIMENTAL: This API is experimental and its interface and behavior is +// subject to change in future releases. This API is not subject to semver +// compatibility guarantees. +func AsMap(m Mappable, dst map[string]any) error { + if dst == nil { + return fmt.Errorf("transform.AsMap: destination map cannot be nil") + } + + for _, k := range m.Keys() { + var val any + if err := m.Get(k, &val); err != nil { + // Allow invalid value errors. Assume they are just nil values. + if !errors.Is(err, blackmagic.InvalidValueError()) { + return fmt.Errorf(`transform.AsMap: failed to get key %q: %w`, k, err) + } + } + dst[k] = val + } + + return nil +} diff --git a/vendor/github.com/lestrrat-go/option/.gitignore b/vendor/github.com/lestrrat-go/option/.gitignore new file mode 100644 index 0000000000..66fd13c903 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/option/LICENSE b/vendor/github.com/lestrrat-go/option/LICENSE new file mode 100644 index 0000000000..188ea7685c --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lestrrat-go + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/option/README.md b/vendor/github.com/lestrrat-go/option/README.md new file mode 100644 index 0000000000..cab0044ed3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/README.md @@ -0,0 +1,245 @@ +# option + +Base object for the "Optional Parameters Pattern". + +# DESCRIPTION + +The beauty of this pattern is that you can achieve a method that can +take the following simple calling style + +```go +obj.Method(mandatory1, mandatory2) +``` + +or the following, if you want to modify its behavior with optional parameters + +```go +obj.Method(mandatory1, mandatory2, optional1, optional2, optional3) +``` + +Instead of the more clunky zero value for optionals style + +```go +obj.Method(mandatory1, mandatory2, nil, "", 0) +``` + +or the equally clunky config object style, which requires you to create a +struct with `NamesThatLookReallyLongBecauseItNeedsToIncludeMethodNamesConfig + +```go +cfg := &ConfigForMethod{ + Optional1: ..., + Optional2: ..., + Optional3: ..., +} +obj.Method(mandatory1, mandatory2, &cfg) +``` + +# SYNOPSIS + +Create an "identifier" for the option. We recommend using an unexported empty struct, +because + +1. It is uniquely identifiable globally +1. Takes minimal space +1. Since it's unexported, you do not have to worry about it leaking elsewhere or having it changed by consumers + +```go +// an unexported empty struct +type identFeatureX struct{} +``` + +Then define a method to create an option using this identifier. Here we assume +that the option will be a boolean option. + +```go +// this is optional, but for readability we usually use a wrapper +// around option.Interface, or a type alias. +type Option +func WithFeatureX(v bool) Option { + // use the constructor to create a new option + return option.New(identFeatureX{}, v) +} +``` + +Now you can create an option, which essentially a two element tuple consisting +of an identifier and its associated value. + +To consume this, you will need to create a function with variadic parameters, +and iterate over the list looking for a particular identifier: + +```go +func MyAwesomeFunc( /* mandatory parameters omitted */, options ...[]Option) { + var enableFeatureX bool + // The nolint directive is recommended if you are using linters such + // as golangci-lint + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identFeatureX{}: + enableFeatureX = option.Value().(bool) + // other cases omitted + } + } + if enableFeatureX { + .... + } +} +``` + +# Option objects + +Option objects take two arguments, its identifier and the value it contains. + +The identifier can be anything, but it's usually better to use a an unexported +empty struct so that only you have the ability to generate said option: + +```go +type identOptionalParamOne struct{} +type identOptionalParamTwo struct{} +type identOptionalParamThree struct{} + +func WithOptionOne(v ...) Option { + return option.New(identOptionalParamOne{}, v) +} +``` + +Then you can call the method we described above as + +```go +obj.Method(m1, m2, WithOptionOne(...), WithOptionTwo(...), WithOptionThree(...)) +``` + +Options should be parsed in a code that looks somewhat like this + +```go +func (obj *Object) Method(m1 Type1, m2 Type2, options ...Option) { + paramOne := defaultValueParamOne + for _, option := range options { + switch option.Ident() { + case identOptionalParamOne{}: + paramOne = option.Value().(...) + } + } + ... +} +``` + +The loop requires a bit of boilerplate, and admittedly, this is the main downside +of this module. However, if you think you want use the Option as a Function pattern, +please check the FAQ below for rationale. + +# Simple usage + +Most of the times all you need to do is to declare the Option type as an alias +in your code: + +```go +package myawesomepkg + +import "github.com/lestrrat-go/option" + +type Option = option.Interface +``` + +Then you can start defining options like they are described in the SYNOPSIS section. + +# Differentiating Options + +When you have multiple methods and options, and those options can only be passed to +each one the methods, it's hard to see which options should be passed to which method. + +```go +func WithX() Option { ... } +func WithY() Option { ... } + +// Now, which of WithX/WithY go to which method? +func (*Obj) Method1(options ...Option) {} +func (*Obj) Method2(options ...Option) {} +``` + +In this case the easiest way to make it obvious is to put an extra layer around +the options so that they have different types + +```go +type Method1Option interface { + Option + method1Option() +} + +type method1Option struct { Option } +func (*method1Option) method1Option() {} + +func WithX() Method1Option { + return &methodOption{option.New(...)} +} + +func (*Obj) Method1(options ...Method1Option) {} +``` + +This way the compiler knows if an option can be passed to a given method. + +# FAQ + +## Why aren't these function-based? + +Using a base option type like `type Option func(ctx interface{})` is certainly one way to achieve the same goal. In this case, you are giving the option itself the ability to "configure" the main object. For example: + +```go +type Foo struct { + optionaValue bool +} + +type Option func(*Foo) error + +func WithOptionalValue(v bool) Option { + return Option(func(f *Foo) error { + f.optionalValue = v + return nil + }) +} + +func NewFoo(options ...Option) (*Foo, error) { + var f Foo + for _, o := range options { + if err := o(&f); err != nil { + return nil, err + } + } + return &f +} +``` + +This in itself is fine, but we think there are a few problems: + +### 1. It's hard to create a reusable "Option" type + +We create many libraries using this optional pattern. We would like to provide a default base object. However, this function based approach is not reusuable because each "Option" type requires that it has a context-specific input type. For example, if the "Option" type in the previous example was `func(interface{}) error`, then its usability will significantly decrease because of the type conversion. + +This is not to say that this library's approach is better as it also requires type conversion to convert the _value_ of the option. However, part of the beauty of the original function based approach was the ease of its use, and we claim that this significantly decreases the merits of the function based approach. + +### 2. The receiver requires exported fields + +Part of the appeal for a function-based option pattern is by giving the option itself the ability to do what it wants, you open up the possibility of allowing third-parties to create options that do things that the library authors did not think about. + +```go +package thirdparty +, but when I read drum sheet music, I kind of get thrown off b/c many times it says to hit the bass drum where I feel like it's a snare hit. +func WithMyAwesomeOption( ... ) mypkg.Option { + return mypkg.Option(func(f *mypkg) error { + f.X = ... + f.Y = ... + f.Z = ... + return nil + }) +} +``` + +However, for any third party code to access and set field values, these fields (`X`, `Y`, `Z`) must be exported. Basically you will need an "open" struct. + +Exported fields are absolutely no problem when you have a struct that represents data alone (i.e., API calls that refer or change state information) happen, but we think that casually expose fields for a library struct is a sure way to maintenance hell in the future. What happens when you want to change the API? What happens when you realize that you want to use the field as state (i.e. use it for more than configuration)? What if they kept referring to that field, and then you have concurrent code accessing it? + +Giving third parties complete access to exported fields is like handing out a loaded weapon to the users, and you are at their mercy. + +Of course, providing public APIs for everything so you can validate and control concurrency is an option, but then ... it's a lot of work, and you may have to provide APIs _only_ so that users can refer it in the option-configuration phase. That sounds like a lot of extra work. + diff --git a/vendor/github.com/lestrrat-go/option/option.go b/vendor/github.com/lestrrat-go/option/option.go new file mode 100644 index 0000000000..bfdbb118c0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/option.go @@ -0,0 +1,38 @@ +package option + +import "fmt" + +// Interface defines the minimum interface that an option must fulfill +type Interface interface { + // Ident returns the "identity" of this option, a unique identifier that + // can be used to differentiate between options + Ident() interface{} + + // Value returns the corresponding value. + Value() interface{} +} + +type pair struct { + ident interface{} + value interface{} +} + +// New creates a new Option +func New(ident, value interface{}) Interface { + return &pair{ + ident: ident, + value: value, + } +} + +func (p *pair) Ident() interface{} { + return p.ident +} + +func (p *pair) Value() interface{} { + return p.value +} + +func (p *pair) String() string { + return fmt.Sprintf(`%v(%v)`, p.ident, p.value) +} diff --git a/vendor/github.com/lestrrat-go/option/v2/.gitignore b/vendor/github.com/lestrrat-go/option/v2/.gitignore new file mode 100644 index 0000000000..66fd13c903 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/lestrrat-go/option/v2/LICENSE b/vendor/github.com/lestrrat-go/option/v2/LICENSE new file mode 100644 index 0000000000..188ea7685c --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 lestrrat-go + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/lestrrat-go/option/v2/README.md b/vendor/github.com/lestrrat-go/option/v2/README.md new file mode 100644 index 0000000000..cab0044ed3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/README.md @@ -0,0 +1,245 @@ +# option + +Base object for the "Optional Parameters Pattern". + +# DESCRIPTION + +The beauty of this pattern is that you can achieve a method that can +take the following simple calling style + +```go +obj.Method(mandatory1, mandatory2) +``` + +or the following, if you want to modify its behavior with optional parameters + +```go +obj.Method(mandatory1, mandatory2, optional1, optional2, optional3) +``` + +Instead of the more clunky zero value for optionals style + +```go +obj.Method(mandatory1, mandatory2, nil, "", 0) +``` + +or the equally clunky config object style, which requires you to create a +struct with `NamesThatLookReallyLongBecauseItNeedsToIncludeMethodNamesConfig + +```go +cfg := &ConfigForMethod{ + Optional1: ..., + Optional2: ..., + Optional3: ..., +} +obj.Method(mandatory1, mandatory2, &cfg) +``` + +# SYNOPSIS + +Create an "identifier" for the option. We recommend using an unexported empty struct, +because + +1. It is uniquely identifiable globally +1. Takes minimal space +1. Since it's unexported, you do not have to worry about it leaking elsewhere or having it changed by consumers + +```go +// an unexported empty struct +type identFeatureX struct{} +``` + +Then define a method to create an option using this identifier. Here we assume +that the option will be a boolean option. + +```go +// this is optional, but for readability we usually use a wrapper +// around option.Interface, or a type alias. +type Option +func WithFeatureX(v bool) Option { + // use the constructor to create a new option + return option.New(identFeatureX{}, v) +} +``` + +Now you can create an option, which essentially a two element tuple consisting +of an identifier and its associated value. + +To consume this, you will need to create a function with variadic parameters, +and iterate over the list looking for a particular identifier: + +```go +func MyAwesomeFunc( /* mandatory parameters omitted */, options ...[]Option) { + var enableFeatureX bool + // The nolint directive is recommended if you are using linters such + // as golangci-lint + //nolint:forcetypeassert + for _, option := range options { + switch option.Ident() { + case identFeatureX{}: + enableFeatureX = option.Value().(bool) + // other cases omitted + } + } + if enableFeatureX { + .... + } +} +``` + +# Option objects + +Option objects take two arguments, its identifier and the value it contains. + +The identifier can be anything, but it's usually better to use a an unexported +empty struct so that only you have the ability to generate said option: + +```go +type identOptionalParamOne struct{} +type identOptionalParamTwo struct{} +type identOptionalParamThree struct{} + +func WithOptionOne(v ...) Option { + return option.New(identOptionalParamOne{}, v) +} +``` + +Then you can call the method we described above as + +```go +obj.Method(m1, m2, WithOptionOne(...), WithOptionTwo(...), WithOptionThree(...)) +``` + +Options should be parsed in a code that looks somewhat like this + +```go +func (obj *Object) Method(m1 Type1, m2 Type2, options ...Option) { + paramOne := defaultValueParamOne + for _, option := range options { + switch option.Ident() { + case identOptionalParamOne{}: + paramOne = option.Value().(...) + } + } + ... +} +``` + +The loop requires a bit of boilerplate, and admittedly, this is the main downside +of this module. However, if you think you want use the Option as a Function pattern, +please check the FAQ below for rationale. + +# Simple usage + +Most of the times all you need to do is to declare the Option type as an alias +in your code: + +```go +package myawesomepkg + +import "github.com/lestrrat-go/option" + +type Option = option.Interface +``` + +Then you can start defining options like they are described in the SYNOPSIS section. + +# Differentiating Options + +When you have multiple methods and options, and those options can only be passed to +each one the methods, it's hard to see which options should be passed to which method. + +```go +func WithX() Option { ... } +func WithY() Option { ... } + +// Now, which of WithX/WithY go to which method? +func (*Obj) Method1(options ...Option) {} +func (*Obj) Method2(options ...Option) {} +``` + +In this case the easiest way to make it obvious is to put an extra layer around +the options so that they have different types + +```go +type Method1Option interface { + Option + method1Option() +} + +type method1Option struct { Option } +func (*method1Option) method1Option() {} + +func WithX() Method1Option { + return &methodOption{option.New(...)} +} + +func (*Obj) Method1(options ...Method1Option) {} +``` + +This way the compiler knows if an option can be passed to a given method. + +# FAQ + +## Why aren't these function-based? + +Using a base option type like `type Option func(ctx interface{})` is certainly one way to achieve the same goal. In this case, you are giving the option itself the ability to "configure" the main object. For example: + +```go +type Foo struct { + optionaValue bool +} + +type Option func(*Foo) error + +func WithOptionalValue(v bool) Option { + return Option(func(f *Foo) error { + f.optionalValue = v + return nil + }) +} + +func NewFoo(options ...Option) (*Foo, error) { + var f Foo + for _, o := range options { + if err := o(&f); err != nil { + return nil, err + } + } + return &f +} +``` + +This in itself is fine, but we think there are a few problems: + +### 1. It's hard to create a reusable "Option" type + +We create many libraries using this optional pattern. We would like to provide a default base object. However, this function based approach is not reusuable because each "Option" type requires that it has a context-specific input type. For example, if the "Option" type in the previous example was `func(interface{}) error`, then its usability will significantly decrease because of the type conversion. + +This is not to say that this library's approach is better as it also requires type conversion to convert the _value_ of the option. However, part of the beauty of the original function based approach was the ease of its use, and we claim that this significantly decreases the merits of the function based approach. + +### 2. The receiver requires exported fields + +Part of the appeal for a function-based option pattern is by giving the option itself the ability to do what it wants, you open up the possibility of allowing third-parties to create options that do things that the library authors did not think about. + +```go +package thirdparty +, but when I read drum sheet music, I kind of get thrown off b/c many times it says to hit the bass drum where I feel like it's a snare hit. +func WithMyAwesomeOption( ... ) mypkg.Option { + return mypkg.Option(func(f *mypkg) error { + f.X = ... + f.Y = ... + f.Z = ... + return nil + }) +} +``` + +However, for any third party code to access and set field values, these fields (`X`, `Y`, `Z`) must be exported. Basically you will need an "open" struct. + +Exported fields are absolutely no problem when you have a struct that represents data alone (i.e., API calls that refer or change state information) happen, but we think that casually expose fields for a library struct is a sure way to maintenance hell in the future. What happens when you want to change the API? What happens when you realize that you want to use the field as state (i.e. use it for more than configuration)? What if they kept referring to that field, and then you have concurrent code accessing it? + +Giving third parties complete access to exported fields is like handing out a loaded weapon to the users, and you are at their mercy. + +Of course, providing public APIs for everything so you can validate and control concurrency is an option, but then ... it's a lot of work, and you may have to provide APIs _only_ so that users can refer it in the option-configuration phase. That sounds like a lot of extra work. + diff --git a/vendor/github.com/lestrrat-go/option/v2/option.go b/vendor/github.com/lestrrat-go/option/v2/option.go new file mode 100644 index 0000000000..f4fcca3b58 --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/option.go @@ -0,0 +1,47 @@ +package option + +import ( + "fmt" + + "github.com/lestrrat-go/blackmagic" +) + +// Interface defines the minimum interface that an option must fulfill +type Interface interface { + // Ident returns the "identity" of this option, a unique identifier that + // can be used to differentiate between options + Ident() any + + // Value assigns the stored value into the dst argument, which must be + // a pointer to a variable that can store the value. If the assignment + // is successful, it return nil, otherwise it returns an error. + Value(dst any) error +} + +type pair[T any] struct { + ident any + value T +} + +// New creates a new Option +func New[T any](ident any, value T) Interface { + return &pair[T]{ + ident: ident, + value: value, + } +} + +func (p *pair[T]) Ident() any { + return p.ident +} + +func (p *pair[T]) Value(dst any) error { + if err := blackmagic.AssignIfCompatible(dst, p.value); err != nil { + return fmt.Errorf("failed to assign value %T to %T: %s", p.value, dst, err) + } + return nil +} + +func (p *pair[T]) String() string { + return fmt.Sprintf(`%v(%v)`, p.ident, p.value) +} diff --git a/vendor/github.com/lestrrat-go/option/v2/set.go b/vendor/github.com/lestrrat-go/option/v2/set.go new file mode 100644 index 0000000000..def943407a --- /dev/null +++ b/vendor/github.com/lestrrat-go/option/v2/set.go @@ -0,0 +1,92 @@ +package option + +import ( + "sync" +) + +// Set is a container to store multiple options. Because options are +// usually used all over the place to configure various aspects of +// a system, it is often useful to be able to collect multiple options +// together and pass them around as a single entity. +// +// Note that Set is meant to be add-only; You usually do not remove +// options from a Set. +// +// The intention is to create a set using a sync.Pool; we would like +// to provide a centralized pool of Sets so that you don't need to +// instantiate a new pool for every type of option you want to +// store, but that is not quite possible because of the limitations +// of parameterized types in Go. Instead create a `*option.SetPool` +// with an appropriate type parameter and allocator. +type Set[T Interface] struct { + mu sync.RWMutex + options []T +} + +func NewSet[T Interface]() *Set[T] { + return &Set[T]{ + options: make([]T, 0, 1), + } +} + +func (s *Set[T]) Add(opt T) { + s.mu.Lock() + defer s.mu.Unlock() + s.options = append(s.options, opt) +} + +func (s *Set[T]) Reset() { + s.mu.Lock() + defer s.mu.Unlock() + s.options = s.options[:0] // Reset the options slice to avoid memory leaks +} + +func (s *Set[T]) Len() int { + s.mu.RLock() + defer s.mu.RUnlock() + return len(s.options) +} + +func (s *Set[T]) Option(i int) T { + var zero T + s.mu.RLock() + defer s.mu.RUnlock() + if i < 0 || i >= len(s.options) { + return zero + } + return s.options[i] +} + +// List returns a slice of all options stored in the Set. +// Note that the slice is the same slice that is used internally, so +// you should not modify the contents of the slice directly. +// This to avoid unnecessary allocations and copying of the slice for +// performance reasons. +func (s *Set[T]) List() []T { + s.mu.RLock() + defer s.mu.RUnlock() + return s.options +} + +// SetPool is a pool of Sets that can be used to efficiently manage +// the lifecycle of Sets. It uses a sync.Pool to store and retrieve +// Sets, allowing for efficient reuse of memory and reducing the +// number of allocations required when creating new Sets. +type SetPool[T Interface] struct { + pool *sync.Pool // sync.Pool that contains *Set[T] +} + +func NewSetPool[T Interface](pool *sync.Pool) *SetPool[T] { + return &SetPool[T]{ + pool: pool, + } +} + +func (p *SetPool[T]) Get() *Set[T] { + return p.pool.Get().(*Set[T]) +} + +func (p *SetPool[T]) Put(s *Set[T]) { + s.Reset() + p.pool.Put(s) +} diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.7.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.7.0.json new file mode 100644 index 0000000000..110c3eca91 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.7.0.json @@ -0,0 +1,4850 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + } + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.8.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.8.0.json new file mode 100644 index 0000000000..0a37621d0c --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.8.0.json @@ -0,0 +1,4867 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + } + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_eddsa", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/config/config.go b/vendor/github.com/open-policy-agent/opa/internal/config/config.go index d4fae5fa65..53dfc6d6cb 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/config/config.go +++ b/vendor/github.com/open-policy-agent/opa/internal/config/config.go @@ -120,8 +120,12 @@ func Load(configFile string, overrides []string, overrideFiles []string) ([]byte // regex looking for ${...} notation strings var envRegex = regexp.MustCompile(`(?U:\${.*})`) -// subEnvVars will look for any environment variables in the passed in string +// SubEnvVars will look for any environment variables in the passed in string // with the syntax of ${VAR_NAME} and replace that string with ENV[VAR_NAME] +func SubEnvVars(s string) string { + return subEnvVars(s) +} + func subEnvVars(s string) string { updatedConfig := envRegex.ReplaceAllStringFunc(s, func(s string) string { // Trim off the '${' and '}' @@ -131,10 +135,14 @@ func subEnvVars(s string) string { } varName := s[2 : len(s)-1] - // Lookup the variable in the environment. We play by - // bash rules.. if its undefined we'll treat it as an - // empty string instead of raising an error. - return os.Getenv(varName) + // Lookup the variable in the environment. We do not + // play by bash rules: if its undefined we'll keep it + // as-is, it could be replaced somewhere down the line. + // If it's set to "", we'll return that. + if lu, ok := os.LookupEnv(varName); ok { + return lu + } + return s }) return updatedConfig diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/buffer/buffer.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/buffer/buffer.go deleted file mode 100644 index c383ff3b54..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/buffer/buffer.go +++ /dev/null @@ -1,112 +0,0 @@ -// Package buffer provides a very thin wrapper around []byte buffer called -// `Buffer`, to provide functionalities that are often used within the jwx -// related packages -package buffer - -import ( - "encoding/base64" - "encoding/binary" - "encoding/json" - "fmt" -) - -// Buffer wraps `[]byte` and provides functions that are often used in -// the jwx related packages. One notable difference is that while -// encoding/json marshalls `[]byte` using base64.StdEncoding, this -// module uses base64.RawURLEncoding as mandated by the spec -type Buffer []byte - -// FromUint creates a `Buffer` from an unsigned int -func FromUint(v uint64) Buffer { - data := make([]byte, 8) - binary.BigEndian.PutUint64(data, v) - - i := 0 - for ; i < len(data); i++ { - if data[i] != 0x0 { - break - } - } - return Buffer(data[i:]) -} - -// FromBase64 constructs a new Buffer from a base64 encoded data -func FromBase64(v []byte) (Buffer, error) { - b := Buffer{} - if err := b.Base64Decode(v); err != nil { - return Buffer(nil), fmt.Errorf("failed to decode from base64: %w", err) - } - - return b, nil -} - -// FromNData constructs a new Buffer from a "n:data" format -// (I made that name up) -func FromNData(v []byte) (Buffer, error) { - size := binary.BigEndian.Uint32(v) - buf := make([]byte, int(size)) - copy(buf, v[4:4+size]) - return Buffer(buf), nil -} - -// Bytes returns the raw bytes that comprises the Buffer -func (b Buffer) Bytes() []byte { - return []byte(b) -} - -// NData returns Datalen || Data, where Datalen is a 32 bit counter for -// the length of the following data, and Data is the octets that comprise -// the buffer data -func (b Buffer) NData() []byte { - buf := make([]byte, 4+b.Len()) - binary.BigEndian.PutUint32(buf, uint32(b.Len())) - - copy(buf[4:], b.Bytes()) - return buf -} - -// Len returns the number of bytes that the Buffer holds -func (b Buffer) Len() int { - return len(b) -} - -// Base64Encode encodes the contents of the Buffer using base64.RawURLEncoding -func (b Buffer) Base64Encode() ([]byte, error) { - enc := base64.RawURLEncoding - out := make([]byte, enc.EncodedLen(len(b))) - enc.Encode(out, b) - return out, nil -} - -// Base64Decode decodes the contents of the Buffer using base64.RawURLEncoding -func (b *Buffer) Base64Decode(v []byte) error { - enc := base64.RawURLEncoding - out := make([]byte, enc.DecodedLen(len(v))) - n, err := enc.Decode(out, v) - if err != nil { - return fmt.Errorf("failed to decode from base64: %w", err) - } - out = out[:n] - *b = Buffer(out) - return nil -} - -// MarshalJSON marshals the buffer into JSON format after encoding the buffer -// with base64.RawURLEncoding -func (b Buffer) MarshalJSON() ([]byte, error) { - v, err := b.Base64Encode() - if err != nil { - return nil, fmt.Errorf("failed to encode to base64: %w", err) - } - return json.Marshal(string(v)) -} - -// UnmarshalJSON unmarshals from a JSON string into a Buffer, after decoding it -// with base64.RawURLEncoding -func (b *Buffer) UnmarshalJSON(data []byte) error { - var x string - if err := json.Unmarshal(data, &x); err != nil { - return fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return b.Base64Decode([]byte(x)) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/elliptic.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/elliptic.go deleted file mode 100644 index b7e35dc707..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/elliptic.go +++ /dev/null @@ -1,11 +0,0 @@ -package jwa - -// EllipticCurveAlgorithm represents the algorithms used for EC keys -type EllipticCurveAlgorithm string - -// Supported values for EllipticCurveAlgorithm -const ( - P256 EllipticCurveAlgorithm = "P-256" - P384 EllipticCurveAlgorithm = "P-384" - P521 EllipticCurveAlgorithm = "P-521" -) diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/key_type.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/key_type.go deleted file mode 100644 index 61d23844a1..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/key_type.go +++ /dev/null @@ -1,67 +0,0 @@ -package jwa - -import ( - "errors" - "fmt" - "strconv" -) - -// KeyType represents the key type ("kty") that are supported -type KeyType string - -var keyTypeAlg = map[string]struct{}{"EC": {}, "oct": {}, "RSA": {}} - -// Supported values for KeyType -const ( - EC KeyType = "EC" // Elliptic Curve - InvalidKeyType KeyType = "" // Invalid KeyType - OctetSeq KeyType = "oct" // Octet sequence (used to represent symmetric keys) - RSA KeyType = "RSA" // RSA -) - -// Accept is used when conversion from values given by -// outside sources (such as JSON payloads) is required -func (keyType *KeyType) Accept(value any) error { - var tmp KeyType - switch x := value.(type) { - case string: - tmp = KeyType(x) - case KeyType: - tmp = x - default: - return fmt.Errorf("invalid type for jwa.KeyType: %T", value) - } - _, ok := keyTypeAlg[tmp.String()] - if !ok { - return errors.New("unknown Key Type algorithm") - } - - *keyType = tmp - return nil -} - -// String returns the string representation of a KeyType -func (keyType KeyType) String() string { - return string(keyType) -} - -// UnmarshalJSON unmarshals and checks data as KeyType Algorithm -func (keyType *KeyType) UnmarshalJSON(data []byte) error { - var quote byte = '"' - var quoted string - if data[0] == quote { - var err error - quoted, err = strconv.Unquote(string(data)) - if err != nil { - return fmt.Errorf("failed to process signature algorithm: %w", err) - } - } else { - quoted = string(data) - } - _, ok := keyTypeAlg[quoted] - if !ok { - return errors.New("unknown signature algorithm") - } - *keyType = KeyType(quoted) - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/parameters.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/parameters.go deleted file mode 100644 index 2fe72e1dbc..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/parameters.go +++ /dev/null @@ -1,29 +0,0 @@ -package jwa - -import ( - "crypto/elliptic" - - "github.com/open-policy-agent/opa/internal/jwx/buffer" -) - -// EllipticCurve provides a indirect type to standard elliptic curve such that we can -// use it for unmarshal -type EllipticCurve struct { - elliptic.Curve -} - -// AlgorithmParameters provides a single structure suitable to unmarshaling any JWK -type AlgorithmParameters struct { - N buffer.Buffer `json:"n,omitempty"` - E buffer.Buffer `json:"e,omitempty"` - D buffer.Buffer `json:"d,omitempty"` - P buffer.Buffer `json:"p,omitempty"` - Q buffer.Buffer `json:"q,omitempty"` - Dp buffer.Buffer `json:"dp,omitempty"` - Dq buffer.Buffer `json:"dq,omitempty"` - Qi buffer.Buffer `json:"qi,omitempty"` - Crv EllipticCurveAlgorithm `json:"crv,omitempty"` - X buffer.Buffer `json:"x,omitempty"` - Y buffer.Buffer `json:"y,omitempty"` - K buffer.Buffer `json:"k,omitempty"` -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/signature.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/signature.go deleted file mode 100644 index c601c46ea9..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwa/signature.go +++ /dev/null @@ -1,78 +0,0 @@ -package jwa - -import ( - "errors" - "fmt" - "strconv" -) - -// SignatureAlgorithm represents the various signature algorithms as described in https://tools.ietf.org/html/rfc7518#section-3.1 -type SignatureAlgorithm string - -var signatureAlg = map[string]struct{}{"ES256": {}, "ES384": {}, "ES512": {}, "HS256": {}, "HS384": {}, "HS512": {}, "PS256": {}, "PS384": {}, "PS512": {}, "RS256": {}, "RS384": {}, "RS512": {}, "none": {}} - -// Supported values for SignatureAlgorithm -const ( - ES256 SignatureAlgorithm = "ES256" // ECDSA using P-256 and SHA-256 - ES384 SignatureAlgorithm = "ES384" // ECDSA using P-384 and SHA-384 - ES512 SignatureAlgorithm = "ES512" // ECDSA using P-521 and SHA-512 - HS256 SignatureAlgorithm = "HS256" // HMAC using SHA-256 - HS384 SignatureAlgorithm = "HS384" // HMAC using SHA-384 - HS512 SignatureAlgorithm = "HS512" // HMAC using SHA-512 - NoSignature SignatureAlgorithm = "none" - PS256 SignatureAlgorithm = "PS256" // RSASSA-PSS using SHA256 and MGF1-SHA256 - PS384 SignatureAlgorithm = "PS384" // RSASSA-PSS using SHA384 and MGF1-SHA384 - PS512 SignatureAlgorithm = "PS512" // RSASSA-PSS using SHA512 and MGF1-SHA512 - RS256 SignatureAlgorithm = "RS256" // RSASSA-PKCS-v1.5 using SHA-256 - RS384 SignatureAlgorithm = "RS384" // RSASSA-PKCS-v1.5 using SHA-384 - RS512 SignatureAlgorithm = "RS512" // RSASSA-PKCS-v1.5 using SHA-512 - NoValue SignatureAlgorithm = "" // No value is different from none - Unsupported SignatureAlgorithm = "unsupported" -) - -// Accept is used when conversion from values given by -// outside sources (such as JSON payloads) is required -func (signature *SignatureAlgorithm) Accept(value any) error { - var tmp SignatureAlgorithm - switch x := value.(type) { - case string: - tmp = SignatureAlgorithm(x) - case SignatureAlgorithm: - tmp = x - default: - return fmt.Errorf("invalid type for jwa.SignatureAlgorithm: %T", value) - } - _, ok := signatureAlg[tmp.String()] - if !ok { - return errors.New("unknown signature algorithm") - } - *signature = tmp - return nil -} - -// String returns the string representation of a SignatureAlgorithm -func (signature SignatureAlgorithm) String() string { - return string(signature) -} - -// UnmarshalJSON unmarshals and checks data as Signature Algorithm -func (signature *SignatureAlgorithm) UnmarshalJSON(data []byte) error { - var quote byte = '"' - var quoted string - if data[0] == quote { - var err error - quoted, err = strconv.Unquote(string(data)) - if err != nil { - return fmt.Errorf("failed to process signature algorithm: %w", err) - } - } else { - quoted = string(data) - } - _, ok := signatureAlg[quoted] - if !ok { - *signature = Unsupported - return nil - } - *signature = SignatureAlgorithm(quoted) - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/ecdsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/ecdsa.go deleted file mode 100644 index 0677f4dc30..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/ecdsa.go +++ /dev/null @@ -1,120 +0,0 @@ -package jwk - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "errors" - "fmt" - "math/big" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -func newECDSAPublicKey(key *ecdsa.PublicKey) (*ECDSAPublicKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.EC) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - - return &ECDSAPublicKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -func newECDSAPrivateKey(key *ecdsa.PrivateKey) (*ECDSAPrivateKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.EC) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - - return &ECDSAPrivateKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -// Materialize returns the EC-DSA public key represented by this JWK -func (k ECDSAPublicKey) Materialize() (any, error) { - return k.key, nil -} - -// Materialize returns the EC-DSA private key represented by this JWK -func (k ECDSAPrivateKey) Materialize() (any, error) { - return k.key, nil -} - -// GenerateKey creates a ECDSAPublicKey from JWK format -func (k *ECDSAPublicKey) GenerateKey(keyJSON *RawKeyJSON) error { - - var x, y big.Int - - if keyJSON.X == nil || keyJSON.Y == nil || keyJSON.Crv == "" { - return errors.New("missing mandatory key parameters X, Y or Crv") - } - - x.SetBytes(keyJSON.X.Bytes()) - y.SetBytes(keyJSON.Y.Bytes()) - - var curve elliptic.Curve - switch keyJSON.Crv { - case jwa.P256: - curve = elliptic.P256() - case jwa.P384: - curve = elliptic.P384() - case jwa.P521: - curve = elliptic.P521() - default: - return fmt.Errorf("invalid curve name %s", keyJSON.Crv) - } - - *k = ECDSAPublicKey{ - StandardHeaders: &keyJSON.StandardHeaders, - key: &ecdsa.PublicKey{ - Curve: curve, - X: &x, - Y: &y, - }, - } - return nil -} - -// GenerateKey creates a ECDSAPrivateKey from JWK format -func (k *ECDSAPrivateKey) GenerateKey(keyJSON *RawKeyJSON) error { - - if keyJSON.D == nil { - return errors.New("missing mandatory key parameter D") - } - eCDSAPublicKey := &ECDSAPublicKey{} - err := eCDSAPublicKey.GenerateKey(keyJSON) - if err != nil { - return fmt.Errorf("failed to generate public key: %w", err) - } - dBytes := keyJSON.D.Bytes() - // The length of this octet string MUST be ceiling(log-base-2(n)/8) - // octets (where n is the order of the curve). This is because the private - // key d must be in the interval [1, n-1] so the bitlength of d should be - // no larger than the bitlength of n-1. The easiest way to find the octet - // length is to take bitlength(n-1), add 7 to force a carry, and shift this - // bit sequence right by 3, which is essentially dividing by 8 and adding - // 1 if there is any remainder. Thus, the private key value d should be - // output to (bitlength(n-1)+7)>>3 octets. - n := eCDSAPublicKey.key.Params().N - octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3 - if octetLength-len(dBytes) != 0 { - return errors.New("failed to generate private key. Incorrect D value") - } - privateKey := &ecdsa.PrivateKey{ - PublicKey: *eCDSAPublicKey.key, - D: (&big.Int{}).SetBytes(keyJSON.D.Bytes()), - } - - k.key = privateKey - k.StandardHeaders = &keyJSON.StandardHeaders - - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/headers.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/headers.go deleted file mode 100644 index b1a6763dda..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/headers.go +++ /dev/null @@ -1,178 +0,0 @@ -package jwk - -import ( - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Convenience constants for common JWK parameters -const ( - AlgorithmKey = "alg" - KeyIDKey = "kid" - KeyOpsKey = "key_ops" - KeyTypeKey = "kty" - KeyUsageKey = "use" - PrivateParamsKey = "privateParams" -) - -// Headers provides a common interface to all future possible headers -type Headers interface { - Get(string) (any, bool) - Set(string, any) error - Walk(func(string, any) error) error - GetAlgorithm() jwa.SignatureAlgorithm - GetKeyID() string - GetKeyOps() KeyOperationList - GetKeyType() jwa.KeyType - GetKeyUsage() string - GetPrivateParams() map[string]any -} - -// StandardHeaders stores the common JWK parameters -type StandardHeaders struct { - Algorithm *jwa.SignatureAlgorithm `json:"alg,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.4 - KeyID string `json:"kid,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.4 - KeyOps KeyOperationList `json:"key_ops,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.3 - KeyType jwa.KeyType `json:"kty,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.1 - KeyUsage string `json:"use,omitempty"` // https://tools.ietf.org/html/rfc7517#section-4.2 - PrivateParams map[string]any `json:"privateParams,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.4 -} - -// GetAlgorithm is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetAlgorithm() jwa.SignatureAlgorithm { - if v := h.Algorithm; v != nil { - return *v - } - return jwa.NoValue -} - -// GetKeyID is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyID() string { - return h.KeyID -} - -// GetKeyOps is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyOps() KeyOperationList { - return h.KeyOps -} - -// GetKeyType is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyType() jwa.KeyType { - return h.KeyType -} - -// GetKeyUsage is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetKeyUsage() string { - return h.KeyUsage -} - -// GetPrivateParams is a convenience function to retrieve the corresponding value stored in the StandardHeaders -func (h *StandardHeaders) GetPrivateParams() map[string]any { - return h.PrivateParams -} - -// Get is a general getter function for JWK StandardHeaders structure -func (h *StandardHeaders) Get(name string) (any, bool) { - switch name { - case AlgorithmKey: - alg := h.GetAlgorithm() - if alg != jwa.NoValue { - return alg, true - } - return nil, false - case KeyIDKey: - v := h.KeyID - if v == "" { - return nil, false - } - return v, true - case KeyOpsKey: - v := h.KeyOps - if v == nil { - return nil, false - } - return v, true - case KeyTypeKey: - v := h.KeyType - if v == jwa.InvalidKeyType { - return nil, false - } - return v, true - case KeyUsageKey: - v := h.KeyUsage - if v == "" { - return nil, false - } - return v, true - case PrivateParamsKey: - v := h.PrivateParams - if len(v) == 0 { - return nil, false - } - return v, true - default: - return nil, false - } -} - -// Set is a general getter function for JWK StandardHeaders structure -func (h *StandardHeaders) Set(name string, value any) error { - switch name { - case AlgorithmKey: - var acceptor jwa.SignatureAlgorithm - if err := acceptor.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", AlgorithmKey, err) - } - h.Algorithm = &acceptor - return nil - case KeyIDKey: - if v, ok := value.(string); ok { - h.KeyID = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", KeyIDKey, value) - case KeyOpsKey: - if err := h.KeyOps.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", KeyOpsKey, err) - } - return nil - case KeyTypeKey: - if err := h.KeyType.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", KeyTypeKey, err) - } - return nil - case KeyUsageKey: - if v, ok := value.(string); ok { - h.KeyUsage = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", KeyUsageKey, value) - case PrivateParamsKey: - if v, ok := value.(map[string]any); ok { - h.PrivateParams = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", PrivateParamsKey, value) - default: - return fmt.Errorf("invalid key: %s", name) - } -} - -// Walk iterates over all JWK standard headers fields while applying a function to its value. -func (h StandardHeaders) Walk(f func(string, any) error) error { - for _, key := range []string{AlgorithmKey, KeyIDKey, KeyOpsKey, KeyTypeKey, KeyUsageKey, PrivateParamsKey} { - if v, ok := h.Get(key); ok { - if err := f(key, v); err != nil { - return fmt.Errorf("walk function returned error for %s: %w", key, err) - } - } - } - - for k, v := range h.PrivateParams { - if err := f(k, v); err != nil { - return fmt.Errorf("walk function returned error for %s: %w", k, err) - } - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/interface.go deleted file mode 100644 index 9c7846269e..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/interface.go +++ /dev/null @@ -1,71 +0,0 @@ -package jwk - -import ( - "crypto/ecdsa" - "crypto/rsa" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Set is a convenience struct to allow generating and parsing -// JWK sets as opposed to single JWKs -type Set struct { - Keys []Key `json:"keys"` -} - -// Key defines the minimal interface for each of the -// key types. Their use and implementation differ significantly -// between each key types, so you should use type assertions -// to perform more specific tasks with each key -type Key interface { - Headers - - // Materialize creates the corresponding key. For example, - // RSA types would create *rsa.PublicKey or *rsa.PrivateKey, - // EC types would create *ecdsa.PublicKey or *ecdsa.PrivateKey, - // and OctetSeq types create a []byte key. - Materialize() (any, error) - GenerateKey(*RawKeyJSON) error -} - -// RawKeyJSON is generic type that represents any kind JWK -type RawKeyJSON struct { - StandardHeaders - jwa.AlgorithmParameters -} - -// RawKeySetJSON is generic type that represents a JWK Set -type RawKeySetJSON struct { - Keys []RawKeyJSON `json:"keys"` -} - -// RSAPublicKey is a type of JWK generated from RSA public keys -type RSAPublicKey struct { - *StandardHeaders - key *rsa.PublicKey -} - -// RSAPrivateKey is a type of JWK generated from RSA private keys -type RSAPrivateKey struct { - *StandardHeaders - *jwa.AlgorithmParameters - key *rsa.PrivateKey -} - -// SymmetricKey is a type of JWK generated from symmetric keys -type SymmetricKey struct { - *StandardHeaders - key []byte -} - -// ECDSAPublicKey is a type of JWK generated from ECDSA public keys -type ECDSAPublicKey struct { - *StandardHeaders - key *ecdsa.PublicKey -} - -// ECDSAPrivateKey is a type of JWK generated from ECDH-ES private keys -type ECDSAPrivateKey struct { - *StandardHeaders - key *ecdsa.PrivateKey -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/jwk.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/jwk.go deleted file mode 100644 index b13245d172..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/jwk.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package jwk implements JWK as described in https://tools.ietf.org/html/rfc7517 -package jwk - -import ( - "crypto/ecdsa" - "crypto/rsa" - "encoding/json" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// GetPublicKey returns the public key based on the private key type. -// For rsa key types *rsa.PublicKey is returned; for ecdsa key types *ecdsa.PublicKey; -// for byte slice (raw) keys, the key itself is returned. If the corresponding -// public key cannot be deduced, an error is returned -func GetPublicKey(key any) (any, error) { - if key == nil { - return nil, errors.New("jwk.New requires a non-nil key") - } - - switch v := key.(type) { - // Mental note: although Public() is defined in both types, - // you can not coalesce the clauses for rsa.PrivateKey and - // ecdsa.PrivateKey, as then `v` becomes any - // b/c the compiler cannot deduce the exact type. - case *rsa.PrivateKey: - return v.Public(), nil - case *ecdsa.PrivateKey: - return v.Public(), nil - case []byte: - return v, nil - default: - return nil, fmt.Errorf("invalid key type %T", key) - } -} - -// GetKeyTypeFromKey creates a jwk.Key from the given key. -func GetKeyTypeFromKey(key any) jwa.KeyType { - - switch key.(type) { - case *rsa.PrivateKey, *rsa.PublicKey: - return jwa.RSA - case *ecdsa.PrivateKey, *ecdsa.PublicKey: - return jwa.EC - case []byte: - return jwa.OctetSeq - default: - return jwa.InvalidKeyType - } -} - -// New creates a jwk.Key from the given key. -func New(key any) (Key, error) { - if key == nil { - return nil, errors.New("jwk.New requires a non-nil key") - } - - switch v := key.(type) { - case *rsa.PrivateKey: - return newRSAPrivateKey(v) - case *rsa.PublicKey: - return newRSAPublicKey(v) - case *ecdsa.PrivateKey: - return newECDSAPrivateKey(v) - case *ecdsa.PublicKey: - return newECDSAPublicKey(v) - case []byte: - return newSymmetricKey(v) - default: - return nil, fmt.Errorf("invalid key type %T", key) - } -} - -func parse(jwkSrc string) (*Set, error) { - - var jwkKeySet Set - var jwkKey Key - rawKeySetJSON := &RawKeySetJSON{} - err := json.Unmarshal([]byte(jwkSrc), rawKeySetJSON) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JWK Set: %w", err) - } - if len(rawKeySetJSON.Keys) == 0 { - - // It might be a single key - rawKeyJSON := &RawKeyJSON{} - err := json.Unmarshal([]byte(jwkSrc), rawKeyJSON) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JWK: %w", err) - } - jwkKey, err = rawKeyJSON.GenerateKey() - if err != nil { - return nil, fmt.Errorf("failed to generate key: %w", err) - } - // Add to set - jwkKeySet.Keys = append(jwkKeySet.Keys, jwkKey) - } else { - for i := range rawKeySetJSON.Keys { - rawKeyJSON := rawKeySetJSON.Keys[i] - if rawKeyJSON.Algorithm != nil && *rawKeyJSON.Algorithm == jwa.Unsupported { - continue - } - jwkKey, err = rawKeyJSON.GenerateKey() - if err != nil { - return nil, fmt.Errorf("failed to generate key: %w", err) - } - jwkKeySet.Keys = append(jwkKeySet.Keys, jwkKey) - } - } - return &jwkKeySet, nil -} - -// ParseBytes parses JWK from the incoming byte buffer. -func ParseBytes(buf []byte) (*Set, error) { - return parse(string(buf)) -} - -// ParseString parses JWK from the incoming string. -func ParseString(s string) (*Set, error) { - return parse(s) -} - -// GenerateKey creates an internal representation of a key from a raw JWK JSON -func (r *RawKeyJSON) GenerateKey() (Key, error) { - - var key Key - - switch r.KeyType { - case jwa.RSA: - if r.D != nil { - key = &RSAPrivateKey{} - } else { - key = &RSAPublicKey{} - } - case jwa.EC: - if r.D != nil { - key = &ECDSAPrivateKey{} - } else { - key = &ECDSAPublicKey{} - } - case jwa.OctetSeq: - key = &SymmetricKey{} - default: - return nil, errors.New("unrecognized key type") - } - err := key.GenerateKey(r) - if err != nil { - return nil, fmt.Errorf("failed to generate key from JWK: %w", err) - } - return key, nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/key_ops.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/key_ops.go deleted file mode 100644 index 628caae4ad..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/key_ops.go +++ /dev/null @@ -1,67 +0,0 @@ -package jwk - -import ( - "encoding/json" - "errors" - "fmt" -) - -// KeyUsageType is used to denote what this key should be used for -type KeyUsageType string - -const ( - // ForSignature is the value used in the headers to indicate that - // this key should be used for signatures - ForSignature KeyUsageType = "sig" - // ForEncryption is the value used in the headers to indicate that - // this key should be used for encryptiong - ForEncryption KeyUsageType = "enc" -) - -// KeyOperation is used to denote the allowed operations for a Key -type KeyOperation string - -// KeyOperationList represents an slice of KeyOperation -type KeyOperationList []KeyOperation - -var keyOps = map[string]struct{}{"sign": {}, "verify": {}, "encrypt": {}, "decrypt": {}, "wrapKey": {}, "unwrapKey": {}, "deriveKey": {}, "deriveBits": {}} - -// KeyOperation constants -const ( - KeyOpSign KeyOperation = "sign" // (compute digital signature or MAC) - KeyOpVerify KeyOperation = "verify" // (verify digital signature or MAC) - KeyOpEncrypt KeyOperation = "encrypt" // (encrypt content) - KeyOpDecrypt KeyOperation = "decrypt" // (decrypt content and validate decryption, if applicable) - KeyOpWrapKey KeyOperation = "wrapKey" // (encrypt key) - KeyOpUnwrapKey KeyOperation = "unwrapKey" // (decrypt key and validate decryption, if applicable) - KeyOpDeriveKey KeyOperation = "deriveKey" // (derive key) - KeyOpDeriveBits KeyOperation = "deriveBits" // (derive bits not to be used as a key) -) - -// Accept determines if Key Operation is valid -func (keyOperationList *KeyOperationList) Accept(v any) error { - switch x := v.(type) { - case KeyOperationList: - *keyOperationList = x - return nil - default: - return fmt.Errorf(`invalid value %T`, v) - } -} - -// UnmarshalJSON unmarshals and checks data as KeyType Algorithm -func (keyOperationList *KeyOperationList) UnmarshalJSON(data []byte) error { - var tempKeyOperationList []string - err := json.Unmarshal(data, &tempKeyOperationList) - if err != nil { - return errors.New("invalid key operation") - } - for _, value := range tempKeyOperationList { - _, ok := keyOps[value] - if !ok { - return errors.New("unknown key operation") - } - *keyOperationList = append(*keyOperationList, KeyOperation(value)) - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/rsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/rsa.go deleted file mode 100644 index d7b5089418..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/rsa.go +++ /dev/null @@ -1,133 +0,0 @@ -package jwk - -import ( - "crypto/rsa" - "encoding/binary" - "errors" - "fmt" - "math/big" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -func newRSAPublicKey(key *rsa.PublicKey) (*RSAPublicKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.RSA) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - return &RSAPublicKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -func newRSAPrivateKey(key *rsa.PrivateKey) (*RSAPrivateKey, error) { - - var hdr StandardHeaders - err := hdr.Set(KeyTypeKey, jwa.RSA) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - - var algoParams jwa.AlgorithmParameters - - // it is needed to use raw encoding to omit the "=" paddings at the end - algoParams.D = key.D.Bytes() - algoParams.P = key.Primes[0].Bytes() - algoParams.Q = key.Primes[1].Bytes() - algoParams.Dp = key.Precomputed.Dp.Bytes() - algoParams.Dq = key.Precomputed.Dq.Bytes() - algoParams.Qi = key.Precomputed.Qinv.Bytes() - - // "modulus" (N) from the public key in the private key - algoParams.N = key.PublicKey.N.Bytes() - - // make the E a.k.a "coprime" - // https://en.wikipedia.org/wiki/RSA_(cryptosystem) - coprime := make([]byte, 8) - binary.BigEndian.PutUint64(coprime, uint64(key.PublicKey.E)) - // find the 1st index of non 0x0 paddings from the beginning - i := 0 - for ; i < len(coprime); i++ { - if coprime[i] != 0x0 { - break - } - } - algoParams.E = coprime[i:] - - return &RSAPrivateKey{ - StandardHeaders: &hdr, - AlgorithmParameters: &algoParams, - key: key, - }, nil -} - -// Materialize returns the standard RSA Public Key representation stored in the internal representation -func (k *RSAPublicKey) Materialize() (any, error) { - if k.key == nil { - return nil, errors.New("key has no rsa.PublicKey associated with it") - } - return k.key, nil -} - -// Materialize returns the standard RSA Private Key representation stored in the internal representation -func (k *RSAPrivateKey) Materialize() (any, error) { - if k.key == nil { - return nil, errors.New("key has no rsa.PrivateKey associated with it") - } - return k.key, nil -} - -// GenerateKey creates a RSAPublicKey from a RawKeyJSON -func (k *RSAPublicKey) GenerateKey(keyJSON *RawKeyJSON) error { - - if keyJSON.N == nil || keyJSON.E == nil { - return errors.New("missing mandatory key parameters N or E") - } - rsaPublicKey := &rsa.PublicKey{ - N: (&big.Int{}).SetBytes(keyJSON.N.Bytes()), - E: int((&big.Int{}).SetBytes(keyJSON.E.Bytes()).Int64()), - } - k.key = rsaPublicKey - k.StandardHeaders = &keyJSON.StandardHeaders - return nil -} - -// GenerateKey creates a RSAPublicKey from a RawKeyJSON -func (k *RSAPrivateKey) GenerateKey(keyJSON *RawKeyJSON) error { - - rsaPublicKey := &RSAPublicKey{} - err := rsaPublicKey.GenerateKey(keyJSON) - if err != nil { - return fmt.Errorf("failed to generate public key: %w", err) - } - - if keyJSON.D == nil || keyJSON.P == nil || keyJSON.Q == nil { - return errors.New("missing mandatory key parameters D, P or Q") - } - privateKey := &rsa.PrivateKey{ - PublicKey: *rsaPublicKey.key, - D: (&big.Int{}).SetBytes(keyJSON.D.Bytes()), - Primes: []*big.Int{ - (&big.Int{}).SetBytes(keyJSON.P.Bytes()), - (&big.Int{}).SetBytes(keyJSON.Q.Bytes()), - }, - } - - if keyJSON.Dp.Len() > 0 { - privateKey.Precomputed.Dp = (&big.Int{}).SetBytes(keyJSON.Dp.Bytes()) - } - if keyJSON.Dq.Len() > 0 { - privateKey.Precomputed.Dq = (&big.Int{}).SetBytes(keyJSON.Dq.Bytes()) - } - if keyJSON.Qi.Len() > 0 { - privateKey.Precomputed.Qinv = (&big.Int{}).SetBytes(keyJSON.Qi.Bytes()) - } - - k.key = privateKey - k.StandardHeaders = &keyJSON.StandardHeaders - k.AlgorithmParameters = &keyJSON.AlgorithmParameters - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/symmetric.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/symmetric.go deleted file mode 100644 index e76189f523..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jwk/symmetric.go +++ /dev/null @@ -1,41 +0,0 @@ -package jwk - -import ( - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -func newSymmetricKey(key []byte) (*SymmetricKey, error) { - var hdr StandardHeaders - - err := hdr.Set(KeyTypeKey, jwa.OctetSeq) - if err != nil { - return nil, fmt.Errorf("failed to set Key Type: %w", err) - } - return &SymmetricKey{ - StandardHeaders: &hdr, - key: key, - }, nil -} - -// Materialize returns the octets for this symmetric key. -// Since this is a symmetric key, this just calls Octets -func (s SymmetricKey) Materialize() (any, error) { - return s.Octets(), nil -} - -// Octets returns the octets in the key -func (s SymmetricKey) Octets() []byte { - return s.key -} - -// GenerateKey creates a Symmetric key from a RawKeyJSON -func (s *SymmetricKey) GenerateKey(keyJSON *RawKeyJSON) error { - - *s = SymmetricKey{ - StandardHeaders: &keyJSON.StandardHeaders, - key: keyJSON.K, - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/headers.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/headers.go deleted file mode 100644 index dcadea43e2..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/headers.go +++ /dev/null @@ -1,154 +0,0 @@ -package jws - -import ( - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Constants for JWS Common parameters -const ( - AlgorithmKey = "alg" - ContentTypeKey = "cty" - CriticalKey = "crit" - JWKKey = "jwk" - JWKSetURLKey = "jku" - KeyIDKey = "kid" - PrivateParamsKey = "privateParams" - TypeKey = "typ" -) - -// Headers provides a common interface for common header parameters -type Headers interface { - Get(string) (any, bool) - Set(string, any) error - GetAlgorithm() jwa.SignatureAlgorithm -} - -// StandardHeaders contains JWS common parameters. -type StandardHeaders struct { - Algorithm jwa.SignatureAlgorithm `json:"alg,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.1 - ContentType string `json:"cty,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.10 - Critical []string `json:"crit,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.11 - JWK string `json:"jwk,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.3 - JWKSetURL string `json:"jku,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.2 - KeyID string `json:"kid,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.4 - PrivateParams map[string]any `json:"privateParams,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.9 - Type string `json:"typ,omitempty"` // https://tools.ietf.org/html/rfc7515#section-4.1.9 -} - -// GetAlgorithm returns algorithm -func (h *StandardHeaders) GetAlgorithm() jwa.SignatureAlgorithm { - return h.Algorithm -} - -// Get is a general getter function for StandardHeaders structure -func (h *StandardHeaders) Get(name string) (any, bool) { - switch name { - case AlgorithmKey: - v := h.Algorithm - if v == "" { - return nil, false - } - return v, true - case ContentTypeKey: - v := h.ContentType - if v == "" { - return nil, false - } - return v, true - case CriticalKey: - v := h.Critical - if len(v) == 0 { - return nil, false - } - return v, true - case JWKKey: - v := h.JWK - if v == "" { - return nil, false - } - return v, true - case JWKSetURLKey: - v := h.JWKSetURL - if v == "" { - return nil, false - } - return v, true - case KeyIDKey: - v := h.KeyID - if v == "" { - return nil, false - } - return v, true - case PrivateParamsKey: - v := h.PrivateParams - if len(v) == 0 { - return nil, false - } - return v, true - case TypeKey: - v := h.Type - if v == "" { - return nil, false - } - return v, true - default: - return nil, false - } -} - -// Set is a general setter function for StandardHeaders structure -func (h *StandardHeaders) Set(name string, value any) error { - switch name { - case AlgorithmKey: - if err := h.Algorithm.Accept(value); err != nil { - return fmt.Errorf("invalid value for %s key: %w", AlgorithmKey, err) - } - return nil - case ContentTypeKey: - if v, ok := value.(string); ok { - h.ContentType = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", ContentTypeKey, value) - case CriticalKey: - if v, ok := value.([]string); ok { - h.Critical = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", CriticalKey, value) - case JWKKey: - if v, ok := value.(string); ok { - h.JWK = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", JWKKey, value) - case JWKSetURLKey: - if v, ok := value.(string); ok { - h.JWKSetURL = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", JWKSetURLKey, value) - case KeyIDKey: - if v, ok := value.(string); ok { - h.KeyID = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", KeyIDKey, value) - case PrivateParamsKey: - if v, ok := value.(map[string]any); ok { - h.PrivateParams = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", PrivateParamsKey, value) - case TypeKey: - if v, ok := value.(string); ok { - h.Type = v - return nil - } - return fmt.Errorf("invalid value for %s key: %T", TypeKey, value) - default: - return fmt.Errorf("invalid key: %s", name) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/interface.go deleted file mode 100644 index e647c8ac93..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/interface.go +++ /dev/null @@ -1,22 +0,0 @@ -package jws - -// Message represents a full JWS encoded message. Flattened serialization -// is not supported as a struct, but rather it's represented as a -// Message struct with only one `Signature` element. -// -// Do not expect to use the Message object to verify or construct a -// signed payloads with. You should only use this when you want to actually -// want to programmatically view the contents for the full JWS Payload. -// -// To sign and verify, use the appropriate `SignWithOption()` nad `Verify()` functions -type Message struct { - Payload []byte `json:"payload"` - Signatures []*Signature `json:"signatures,omitempty"` -} - -// Signature represents the headers and signature of a JWS message -type Signature struct { - Headers Headers `json:"header,omitempty"` // Unprotected Headers - Protected Headers `json:"Protected,omitempty"` // Protected Headers - Signature []byte `json:"signature,omitempty"` // GetSignature -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/jws.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/jws.go deleted file mode 100644 index b2b2248306..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/jws.go +++ /dev/null @@ -1,220 +0,0 @@ -// Package jws implements the digital Signature on JSON based data -// structures as described in https://tools.ietf.org/html/rfc7515 -// -// If you do not care about the details, the only things that you -// would need to use are the following functions: -// -// jws.SignWithOption(Payload, algorithm, key) -// jws.Verify(encodedjws, algorithm, key) -// -// To sign, simply use `jws.SignWithOption`. `Payload` is a []byte buffer that -// contains whatever data you want to sign. `alg` is one of the -// jwa.SignatureAlgorithm constants from package jwa. For RSA and -// ECDSA family of algorithms, you will need to prepare a private key. -// For HMAC family, you just need a []byte value. The `jws.SignWithOption` -// function will return the encoded JWS message on success. -// -// To verify, use `jws.Verify`. It will parse the `encodedjws` buffer -// and verify the result using `algorithm` and `key`. Upon successful -// verification, the original Payload is returned, so you can work on it. -package jws - -import ( - "bytes" - "crypto/rand" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "strings" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jwk" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" - "github.com/open-policy-agent/opa/internal/jwx/jws/verify" -) - -// SignLiteral generates a Signature for the given Payload and Headers, and serializes -// it in compact serialization format. In this format you may NOT use -// multiple signers. -func SignLiteral(payload []byte, alg jwa.SignatureAlgorithm, key any, hdrBuf []byte, rnd io.Reader) ([]byte, error) { - encodedHdr := base64.RawURLEncoding.EncodeToString(hdrBuf) - encodedPayload := base64.RawURLEncoding.EncodeToString(payload) - signingInput := strings.Join( - []string{ - encodedHdr, - encodedPayload, - }, ".", - ) - signer, err := sign.New(alg) - if err != nil { - return nil, fmt.Errorf("failed to create signer: %w", err) - } - - var signature []byte - switch s := signer.(type) { - case *sign.ECDSASigner: - signature, err = s.SignWithRand([]byte(signingInput), key, rnd) - default: - signature, err = signer.Sign([]byte(signingInput), key) - } - if err != nil { - return nil, fmt.Errorf("failed to sign Payload: %w", err) - } - encodedSignature := base64.RawURLEncoding.EncodeToString(signature) - compactSerialization := strings.Join( - []string{ - signingInput, - encodedSignature, - }, ".", - ) - return []byte(compactSerialization), nil -} - -// SignWithOption generates a Signature for the given Payload, and serializes -// it in compact serialization format. In this format you may NOT use -// multiple signers. -// -// If you would like to pass custom Headers, use the WithHeaders option. -func SignWithOption(payload []byte, alg jwa.SignatureAlgorithm, key any) ([]byte, error) { - var headers Headers = &StandardHeaders{} - - err := headers.Set(AlgorithmKey, alg) - if err != nil { - return nil, fmt.Errorf("failed to set alg value: %w", err) - } - - hdrBuf, err := json.Marshal(headers) - if err != nil { - return nil, fmt.Errorf("failed to marshal Headers: %w", err) - } - // NOTE(sr): we don't use SignWithOption -- if we did, this rand.Reader - // should come from the BuiltinContext's Seed, too. - return SignLiteral(payload, alg, key, hdrBuf, rand.Reader) -} - -// Verify checks if the given JWS message is verifiable using `alg` and `key`. -// If the verification is successful, `err` is nil, and the content of the -// Payload that was signed is returned. If you need more fine-grained -// control of the verification process, manually call `Parse`, generate a -// verifier, and call `Verify` on the parsed JWS message object. -func Verify(buf []byte, alg jwa.SignatureAlgorithm, key any) (ret []byte, err error) { - - verifier, err := verify.New(alg) - if err != nil { - return nil, fmt.Errorf("failed to create verifier: %w", err) - } - - buf = bytes.TrimSpace(buf) - if len(buf) == 0 { - return nil, errors.New(`attempt to verify empty buffer`) - } - - parts, err := SplitCompact(string(buf)) - if err != nil { - return nil, fmt.Errorf("failed extract from compact serialization format: %w", err) - } - - signingInput := strings.Join( - []string{ - parts[0], - parts[1], - }, ".", - ) - - decodedSignature, err := base64.RawURLEncoding.DecodeString(parts[2]) - if err != nil { - return nil, fmt.Errorf("failed to decode signature: %w", err) - } - if err := verifier.Verify([]byte(signingInput), decodedSignature, key); err != nil { - return nil, fmt.Errorf("failed to verify message: %w", err) - } - - if decodedPayload, err := base64.RawURLEncoding.DecodeString(parts[1]); err == nil { - return decodedPayload, nil - } - return nil, fmt.Errorf("failed to decode Payload: %w", err) -} - -// VerifyWithJWK verifies the JWS message using the specified JWK -func VerifyWithJWK(buf []byte, key jwk.Key) (payload []byte, err error) { - - keyVal, err := key.Materialize() - if err != nil { - return nil, fmt.Errorf("failed to materialize key: %w", err) - } - return Verify(buf, key.GetAlgorithm(), keyVal) -} - -// VerifyWithJWKSet verifies the JWS message using JWK key set. -// By default it will only pick up keys that have the "use" key -// set to either "sig" or "enc", but you can override it by -// providing a keyaccept function. -func VerifyWithJWKSet(buf []byte, keyset *jwk.Set) (payload []byte, err error) { - - for _, key := range keyset.Keys { - payload, err := VerifyWithJWK(buf, key) - if err == nil { - return payload, nil - } - } - return nil, errors.New("failed to verify with any of the keys") -} - -// ParseByte parses a JWS value serialized via compact serialization and provided as []byte. -func ParseByte(jwsCompact []byte) (m *Message, err error) { - return parseCompact(string(jwsCompact)) -} - -// ParseString parses a JWS value serialized via compact serialization and provided as string. -func ParseString(s string) (*Message, error) { - return parseCompact(s) -} - -// SplitCompact splits a JWT and returns its three parts -// separately: Protected Headers, Payload and Signature. -func SplitCompact(jwsCompact string) ([]string, error) { - - parts := strings.Split(jwsCompact, ".") - if len(parts) < 3 { - return nil, errors.New("failed to split compact serialization") - } - return parts, nil -} - -// parseCompact parses a JWS value serialized via compact serialization. -func parseCompact(str string) (m *Message, err error) { - - var decodedHeader, decodedPayload, decodedSignature []byte - parts, err := SplitCompact(str) - if err != nil { - return nil, fmt.Errorf("invalid compact serialization format: %w", err) - } - - if decodedHeader, err = base64.RawURLEncoding.DecodeString(parts[0]); err != nil { - return nil, fmt.Errorf("failed to decode Headers: %w", err) - } - var hdr StandardHeaders - if err := json.Unmarshal(decodedHeader, &hdr); err != nil { - return nil, fmt.Errorf("failed to parse JOSE Headers: %w", err) - } - - if decodedPayload, err = base64.RawURLEncoding.DecodeString(parts[1]); err != nil { - return nil, fmt.Errorf("failed to decode Payload: %w", err) - } - - if len(parts) > 2 { - if decodedSignature, err = base64.RawURLEncoding.DecodeString(parts[2]); err != nil { - return nil, fmt.Errorf("failed to decode Signature: %w", err) - } - } - - var msg Message - msg.Payload = decodedPayload - msg.Signatures = append(msg.Signatures, &Signature{ - Protected: &hdr, - Signature: decodedSignature, - }) - return &msg, nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/message.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/message.go deleted file mode 100644 index 1366a3d7be..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/message.go +++ /dev/null @@ -1,26 +0,0 @@ -package jws - -// PublicHeaders returns the public headers in a JWS -func (s Signature) PublicHeaders() Headers { - return s.Headers -} - -// ProtectedHeaders returns the protected headers in a JWS -func (s Signature) ProtectedHeaders() Headers { - return s.Protected -} - -// GetSignature returns the signature in a JWS -func (s Signature) GetSignature() []byte { - return s.Signature -} - -// GetPayload returns the payload in a JWS -func (m Message) GetPayload() []byte { - return m.Payload -} - -// GetSignatures returns the all signatures in a JWS -func (m Message) GetSignatures() []*Signature { - return m.Signatures -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/ecdsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/ecdsa.go deleted file mode 100644 index 5f3e8accad..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/ecdsa.go +++ /dev/null @@ -1,90 +0,0 @@ -package sign - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rand" - "errors" - "fmt" - "io" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var ecdsaSignFuncs = map[jwa.SignatureAlgorithm]ecdsaSignFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]crypto.Hash{ - jwa.ES256: crypto.SHA256, - jwa.ES384: crypto.SHA384, - jwa.ES512: crypto.SHA512, - } - - for alg, h := range algs { - ecdsaSignFuncs[alg] = makeECDSASignFunc(h) - } -} - -func makeECDSASignFunc(hash crypto.Hash) ecdsaSignFunc { - return ecdsaSignFunc(func(payload []byte, key *ecdsa.PrivateKey, rnd io.Reader) ([]byte, error) { - curveBits := key.Curve.Params().BitSize - keyBytes := curveBits / 8 - // Curve bits do not need to be a multiple of 8. - if curveBits%8 > 0 { - keyBytes++ - } - h := hash.New() - h.Write(payload) - r, s, err := ecdsa.Sign(rnd, key, h.Sum(nil)) - if err != nil { - return nil, fmt.Errorf("failed to sign payload using ecdsa: %w", err) - } - - rBytes := r.Bytes() - rBytesPadded := make([]byte, keyBytes) - copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) - - sBytes := s.Bytes() - sBytesPadded := make([]byte, keyBytes) - copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) - - out := append(rBytesPadded, sBytesPadded...) - return out, nil - }) -} - -func newECDSA(alg jwa.SignatureAlgorithm) (*ECDSASigner, error) { - signfn, ok := ecdsaSignFuncs[alg] - if !ok { - return nil, fmt.Errorf("unsupported algorithm while trying to create ECDSA signer: %s", alg) - } - - return &ECDSASigner{ - alg: alg, - sign: signfn, - }, nil -} - -// Algorithm returns the signer algorithm -func (s ECDSASigner) Algorithm() jwa.SignatureAlgorithm { - return s.alg -} - -// SignWithRand signs payload with a ECDSA private key and a provided randomness -// source (such as `rand.Reader`). -func (s ECDSASigner) SignWithRand(payload []byte, key any, r io.Reader) ([]byte, error) { - if key == nil { - return nil, errors.New("missing private key while signing payload") - } - - privateKey, ok := key.(*ecdsa.PrivateKey) - if !ok { - return nil, fmt.Errorf("invalid key type %T. *ecdsa.PrivateKey is required", key) - } - return s.sign(payload, privateKey, r) -} - -// Sign signs payload with a ECDSA private key -func (s ECDSASigner) Sign(payload []byte, key any) ([]byte, error) { - return s.SignWithRand(payload, key, rand.Reader) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/hmac.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/hmac.go deleted file mode 100644 index de541755ef..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/hmac.go +++ /dev/null @@ -1,66 +0,0 @@ -package sign - -import ( - "crypto/hmac" - "crypto/sha256" - "crypto/sha512" - "errors" - "fmt" - "hash" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var hmacSignFuncs = map[jwa.SignatureAlgorithm]hmacSignFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]func() hash.Hash{ - jwa.HS256: sha256.New, - jwa.HS384: sha512.New384, - jwa.HS512: sha512.New, - } - - for alg, h := range algs { - hmacSignFuncs[alg] = makeHMACSignFunc(h) - - } -} - -func newHMAC(alg jwa.SignatureAlgorithm) (*HMACSigner, error) { - signer, ok := hmacSignFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create HMAC signer: %s`, alg) - } - - return &HMACSigner{ - alg: alg, - sign: signer, - }, nil -} - -func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc { - return hmacSignFunc(func(payload []byte, key []byte) ([]byte, error) { - h := hmac.New(hfunc, key) - h.Write(payload) - return h.Sum(nil), nil - }) -} - -// Algorithm returns the signer algorithm -func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm { - return s.alg -} - -// Sign signs payload with a Symmetric key -func (s HMACSigner) Sign(payload []byte, key any) ([]byte, error) { - hmackey, ok := key.([]byte) - if !ok { - return nil, fmt.Errorf(`invalid key type %T. []byte is required`, key) - } - - if len(hmackey) == 0 { - return nil, errors.New(`missing key while signing payload`) - } - - return s.sign(payload, hmackey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/interface.go deleted file mode 100644 index 25b592ed4e..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -package sign - -import ( - "crypto/ecdsa" - "crypto/rsa" - "io" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// Signer provides a common interface for supported alg signing methods -type Signer interface { - // Sign creates a signature for the given `payload`. - // `key` is the key used for signing the payload, and is usually - // the private key type associated with the signature method. For example, - // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the - // `*"crypto/rsa".PrivateKey` type. - // Check the documentation for each signer for details - Sign(payload []byte, key any) ([]byte, error) - - Algorithm() jwa.SignatureAlgorithm -} - -type rsaSignFunc func([]byte, *rsa.PrivateKey) ([]byte, error) - -// RSASigner uses crypto/rsa to sign the payloads. -type RSASigner struct { - alg jwa.SignatureAlgorithm - sign rsaSignFunc -} - -type ecdsaSignFunc func([]byte, *ecdsa.PrivateKey, io.Reader) ([]byte, error) - -// ECDSASigner uses crypto/ecdsa to sign the payloads. -type ECDSASigner struct { - alg jwa.SignatureAlgorithm - sign ecdsaSignFunc -} - -type hmacSignFunc func([]byte, []byte) ([]byte, error) - -// HMACSigner uses crypto/hmac to sign the payloads. -type HMACSigner struct { - alg jwa.SignatureAlgorithm - sign hmacSignFunc -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/rsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/rsa.go deleted file mode 100644 index a671b7318a..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/rsa.go +++ /dev/null @@ -1,97 +0,0 @@ -package sign - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var rsaSignFuncs = map[jwa.SignatureAlgorithm]rsaSignFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]struct { - Hash crypto.Hash - SignFunc func(crypto.Hash) rsaSignFunc - }{ - jwa.RS256: { - Hash: crypto.SHA256, - SignFunc: makeSignPKCS1v15, - }, - jwa.RS384: { - Hash: crypto.SHA384, - SignFunc: makeSignPKCS1v15, - }, - jwa.RS512: { - Hash: crypto.SHA512, - SignFunc: makeSignPKCS1v15, - }, - jwa.PS256: { - Hash: crypto.SHA256, - SignFunc: makeSignPSS, - }, - jwa.PS384: { - Hash: crypto.SHA384, - SignFunc: makeSignPSS, - }, - jwa.PS512: { - Hash: crypto.SHA512, - SignFunc: makeSignPSS, - }, - } - - for alg, item := range algs { - rsaSignFuncs[alg] = item.SignFunc(item.Hash) - } -} - -func makeSignPKCS1v15(hash crypto.Hash) rsaSignFunc { - return rsaSignFunc(func(payload []byte, key *rsa.PrivateKey) ([]byte, error) { - h := hash.New() - h.Write(payload) - return rsa.SignPKCS1v15(rand.Reader, key, hash, h.Sum(nil)) - }) -} - -func makeSignPSS(hash crypto.Hash) rsaSignFunc { - return rsaSignFunc(func(payload []byte, key *rsa.PrivateKey) ([]byte, error) { - h := hash.New() - h.Write(payload) - return rsa.SignPSS(rand.Reader, key, hash, h.Sum(nil), &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthAuto, - }) - }) -} - -func newRSA(alg jwa.SignatureAlgorithm) (*RSASigner, error) { - signfn, ok := rsaSignFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create RSA signer: %s`, alg) - } - return &RSASigner{ - alg: alg, - sign: signfn, - }, nil -} - -// Algorithm returns the signer algorithm -func (s RSASigner) Algorithm() jwa.SignatureAlgorithm { - return s.alg -} - -// Sign creates a signature using crypto/rsa. key must be a non-nil instance of -// `*"crypto/rsa".PrivateKey`. -func (s RSASigner) Sign(payload []byte, key any) ([]byte, error) { - if key == nil { - return nil, errors.New(`missing private key while signing payload`) - } - rsakey, ok := key.(*rsa.PrivateKey) - if !ok { - return nil, fmt.Errorf(`invalid key type %T. *rsa.PrivateKey is required`, key) - } - - return s.sign(payload, rsakey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/sign.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/sign.go deleted file mode 100644 index c1432236fb..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/sign/sign.go +++ /dev/null @@ -1,66 +0,0 @@ -package sign - -import ( - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// New creates a signer that signs payloads using the given signature algorithm. -func New(alg jwa.SignatureAlgorithm) (Signer, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512: - return newRSA(alg) - case jwa.ES256, jwa.ES384, jwa.ES512: - return newECDSA(alg) - case jwa.HS256, jwa.HS384, jwa.HS512: - return newHMAC(alg) - default: - return nil, fmt.Errorf(`unsupported signature algorithm %s`, alg) - } -} - -// GetSigningKey returns a *rsa.PrivateKey or *ecdsa.PrivateKey typically encoded in PEM blocks of type "RSA PRIVATE KEY" -// or "EC PRIVATE KEY" for RSA and ECDSA family of algorithms. -// For HMAC family, it return a []byte value -func GetSigningKey(key string, alg jwa.SignatureAlgorithm) (any, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512: - block, _ := pem.Decode([]byte(key)) - if block == nil { - return nil, errors.New("failed to parse PEM block containing the key") - } - - priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - pkcs8priv, err2 := x509.ParsePKCS8PrivateKey(block.Bytes) - if err2 != nil { - return nil, fmt.Errorf("error parsing private key (%v), (%v)", err, err2) - } - return pkcs8priv, nil - } - return priv, nil - case jwa.ES256, jwa.ES384, jwa.ES512: - block, _ := pem.Decode([]byte(key)) - if block == nil { - return nil, errors.New("failed to parse PEM block containing the key") - } - - priv, err := x509.ParseECPrivateKey(block.Bytes) - if err != nil { - pkcs8priv, err2 := x509.ParsePKCS8PrivateKey(block.Bytes) - if err2 != nil { - return nil, fmt.Errorf("error parsing private key (%v), (%v)", err, err2) - } - return pkcs8priv, nil - } - return priv, nil - case jwa.HS256, jwa.HS384, jwa.HS512: - return []byte(key), nil - default: - return nil, fmt.Errorf("unsupported signature algorithm: %s", alg) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/ecdsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/ecdsa.go deleted file mode 100644 index ba32078ac9..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/ecdsa.go +++ /dev/null @@ -1,67 +0,0 @@ -package verify - -import ( - "crypto" - "crypto/ecdsa" - "errors" - "fmt" - "math/big" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var ecdsaVerifyFuncs = map[jwa.SignatureAlgorithm]ecdsaVerifyFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]crypto.Hash{ - jwa.ES256: crypto.SHA256, - jwa.ES384: crypto.SHA384, - jwa.ES512: crypto.SHA512, - } - - for alg, h := range algs { - ecdsaVerifyFuncs[alg] = makeECDSAVerifyFunc(h) - } -} - -func makeECDSAVerifyFunc(hash crypto.Hash) ecdsaVerifyFunc { - return ecdsaVerifyFunc(func(payload []byte, signature []byte, key *ecdsa.PublicKey) error { - - r, s := &big.Int{}, &big.Int{} - n := len(signature) / 2 - r.SetBytes(signature[:n]) - s.SetBytes(signature[n:]) - - h := hash.New() - h.Write(payload) - - if !ecdsa.Verify(key, h.Sum(nil), r, s) { - return errors.New(`failed to verify signature using ecdsa`) - } - return nil - }) -} - -func newECDSA(alg jwa.SignatureAlgorithm) (*ECDSAVerifier, error) { - verifyfn, ok := ecdsaVerifyFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create ECDSA verifier: %s`, alg) - } - - return &ECDSAVerifier{ - verify: verifyfn, - }, nil -} - -// Verify checks whether the signature for a given input and key is correct -func (v ECDSAVerifier) Verify(payload []byte, signature []byte, key any) error { - if key == nil { - return errors.New(`missing public key while verifying payload`) - } - ecdsakey, ok := key.(*ecdsa.PublicKey) - if !ok { - return fmt.Errorf(`invalid key type %T. *ecdsa.PublicKey is required`, key) - } - - return v.verify(payload, signature, ecdsakey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/hmac.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/hmac.go deleted file mode 100644 index 25651a0f8d..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/hmac.go +++ /dev/null @@ -1,33 +0,0 @@ -package verify - -import ( - "crypto/hmac" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" -) - -func newHMAC(alg jwa.SignatureAlgorithm) (*HMACVerifier, error) { - - s, err := sign.New(alg) - if err != nil { - return nil, fmt.Errorf("failed to generate HMAC signer: %w", err) - } - return &HMACVerifier{signer: s}, nil -} - -// Verify checks whether the signature for a given input and key is correct -func (v HMACVerifier) Verify(signingInput, signature []byte, key any) (err error) { - - expected, err := v.signer.Sign(signingInput, key) - if err != nil { - return fmt.Errorf("failed to generated signature: %w", err) - } - - if !hmac.Equal(signature, expected) { - return errors.New("failed to match hmac signature") - } - return nil -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/interface.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/interface.go deleted file mode 100644 index e72c3ed7f7..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/interface.go +++ /dev/null @@ -1,39 +0,0 @@ -package verify - -import ( - "crypto/ecdsa" - "crypto/rsa" - - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" -) - -// Verifier provides a common interface for supported alg verification methods -type Verifier interface { - // Verify checks whether the payload and signature are valid for - // the given key. - // `key` is the key used for verifying the payload, and is usually - // the public key associated with the signature method. For example, - // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the - // `*"crypto/rsa".PublicKey` type. - // Check the documentation for each verifier for details - Verify(payload []byte, signature []byte, key any) error -} - -type rsaVerifyFunc func([]byte, []byte, *rsa.PublicKey) error - -// RSAVerifier implements the Verifier interface -type RSAVerifier struct { - verify rsaVerifyFunc -} - -type ecdsaVerifyFunc func([]byte, []byte, *ecdsa.PublicKey) error - -// ECDSAVerifier implements the Verifier interface -type ECDSAVerifier struct { - verify ecdsaVerifyFunc -} - -// HMACVerifier implements the Verifier interface -type HMACVerifier struct { - signer sign.Signer -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/rsa.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/rsa.go deleted file mode 100644 index 163ff84bcf..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/rsa.go +++ /dev/null @@ -1,88 +0,0 @@ -package verify - -import ( - "crypto" - "crypto/rsa" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -var rsaVerifyFuncs = map[jwa.SignatureAlgorithm]rsaVerifyFunc{} - -func init() { - algs := map[jwa.SignatureAlgorithm]struct { - Hash crypto.Hash - VerifyFunc func(crypto.Hash) rsaVerifyFunc - }{ - jwa.RS256: { - Hash: crypto.SHA256, - VerifyFunc: makeVerifyPKCS1v15, - }, - jwa.RS384: { - Hash: crypto.SHA384, - VerifyFunc: makeVerifyPKCS1v15, - }, - jwa.RS512: { - Hash: crypto.SHA512, - VerifyFunc: makeVerifyPKCS1v15, - }, - jwa.PS256: { - Hash: crypto.SHA256, - VerifyFunc: makeVerifyPSS, - }, - jwa.PS384: { - Hash: crypto.SHA384, - VerifyFunc: makeVerifyPSS, - }, - jwa.PS512: { - Hash: crypto.SHA512, - VerifyFunc: makeVerifyPSS, - }, - } - - for alg, item := range algs { - rsaVerifyFuncs[alg] = item.VerifyFunc(item.Hash) - } -} - -func makeVerifyPKCS1v15(hash crypto.Hash) rsaVerifyFunc { - return rsaVerifyFunc(func(payload, signature []byte, key *rsa.PublicKey) error { - h := hash.New() - h.Write(payload) - return rsa.VerifyPKCS1v15(key, hash, h.Sum(nil), signature) - }) -} - -func makeVerifyPSS(hash crypto.Hash) rsaVerifyFunc { - return rsaVerifyFunc(func(payload, signature []byte, key *rsa.PublicKey) error { - h := hash.New() - h.Write(payload) - return rsa.VerifyPSS(key, hash, h.Sum(nil), signature, nil) - }) -} - -func newRSA(alg jwa.SignatureAlgorithm) (*RSAVerifier, error) { - verifyfn, ok := rsaVerifyFuncs[alg] - if !ok { - return nil, fmt.Errorf(`unsupported algorithm while trying to create RSA verifier: %s`, alg) - } - - return &RSAVerifier{ - verify: verifyfn, - }, nil -} - -// Verify checks if a JWS is valid. -func (v RSAVerifier) Verify(payload, signature []byte, key any) error { - if key == nil { - return errors.New(`missing public key while verifying payload`) - } - rsaKey, ok := key.(*rsa.PublicKey) - if !ok { - return fmt.Errorf(`invalid key type %T. *rsa.PublicKey is required`, key) - } - - return v.verify(payload, signature, rsaKey) -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/verify.go b/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/verify.go deleted file mode 100644 index 7370b4a2f1..0000000000 --- a/vendor/github.com/open-policy-agent/opa/internal/jwx/jws/verify/verify.go +++ /dev/null @@ -1,56 +0,0 @@ -package verify - -import ( - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - - "github.com/open-policy-agent/opa/internal/jwx/jwa" -) - -// New creates a new JWS verifier using the specified algorithm -// and the public key -func New(alg jwa.SignatureAlgorithm) (Verifier, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512: - return newRSA(alg) - case jwa.ES256, jwa.ES384, jwa.ES512: - return newECDSA(alg) - case jwa.HS256, jwa.HS384, jwa.HS512: - return newHMAC(alg) - default: - return nil, fmt.Errorf(`unsupported signature algorithm: %s`, alg) - } -} - -// GetSigningKey returns a *rsa.PublicKey or *ecdsa.PublicKey typically encoded in PEM blocks of type "PUBLIC KEY", -// for RSA and ECDSA family of algorithms. -// For HMAC family, it return a []byte value -func GetSigningKey(key string, alg jwa.SignatureAlgorithm) (any, error) { - switch alg { - case jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512, jwa.ES256, jwa.ES384, jwa.ES512: - block, _ := pem.Decode([]byte(key)) - if block == nil { - return nil, errors.New("failed to parse PEM block containing the key") - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return nil, err - } - - switch pub := pub.(type) { - case *rsa.PublicKey, *ecdsa.PublicKey: - return pub, nil - default: - return nil, fmt.Errorf("invalid key type %T", pub) - } - case jwa.HS256, jwa.HS384, jwa.HS512: - return []byte(key), nil - default: - return nil, fmt.Errorf("unsupported signature algorithm: %s", alg) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/internal/report/report.go b/vendor/github.com/open-policy-agent/opa/internal/report/report.go index b517864ed3..bc71d66a3c 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/report/report.go +++ b/vendor/github.com/open-policy-agent/opa/internal/report/report.go @@ -6,17 +6,19 @@ package report import ( + "cmp" "context" "encoding/json" + "errors" "fmt" "net/http" "os" "runtime" "strconv" "strings" - "sync" "time" + "github.com/open-policy-agent/opa/internal/semver" "github.com/open-policy-agent/opa/v1/keys" "github.com/open-policy-agent/opa/v1/logging" "github.com/open-policy-agent/opa/v1/version" @@ -25,24 +27,25 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) -// ExternalServiceURL is the base HTTP URL for a telemetry service. -// If not otherwise specified it will use the hard coded default. +// ExternalServiceURL is the base HTTP URL for a github instance used +// to query for more recent version. +// If not otherwise specified, it will use the hard-coded default, api.github.com. +// GHRepo is the repository to use, and defaults to "open-policy-agent/opa" // // Override at build time via: // // -ldflags "-X github.com/open-policy-agent/opa/internal/report.ExternalServiceURL=" +// -ldflags "-X github.com/open-policy-agent/opa/internal/report.GHRepo=" // -// This will be overridden if the OPA_TELEMETRY_SERVICE_URL environment variable +// ExternalServiceURL will be overridden if the OPA_TELEMETRY_SERVICE_URL environment variable // is provided. -var ExternalServiceURL = "https://telemetry.openpolicyagent.org" +var ExternalServiceURL = "https://api.github.com" +var GHRepo = "open-policy-agent/opa" // Reporter reports information such as the version, heap usage about the running OPA instance to an external service -type Reporter struct { - body map[string]any - client rest.Client - - gatherers map[string]Gatherer - gatherersMtx sync.Mutex +type Reporter interface { + SendReport(ctx context.Context) (*DataResponse, error) + RegisterGatherer(key string, f Gatherer) } // Gatherer represents a mechanism to inject additional data in the telemetry report @@ -50,7 +53,7 @@ type Gatherer func(ctx context.Context) (any, error) // DataResponse represents the data returned by the external service type DataResponse struct { - Latest ReleaseDetails `json:"latest,omitempty"` + Latest ReleaseDetails `json:"latest"` } // ReleaseDetails holds information about the latest OPA release @@ -66,20 +69,21 @@ type Options struct { Logger logging.Logger } -// New returns an instance of the Reporter -func New(id string, opts Options) (*Reporter, error) { - r := Reporter{ - gatherers: map[string]Gatherer{}, - } - r.body = map[string]any{ - "id": id, - "version": version.Version, - } +type GHVersionCollector struct { + client rest.Client +} - url := os.Getenv("OPA_TELEMETRY_SERVICE_URL") - if url == "" { - url = ExternalServiceURL - } +type GHResponse struct { + TagName string `json:"tag_name,omitempty"` // latest OPA release tag + ReleaseNotes string `json:"html_url,omitempty"` // link to the OPA release notes + Download string `json:"assets_url,omitempty"` // link to download the OPA release +} + +// New returns an instance of the Reporter +func New(opts Options) (Reporter, error) { + r := GHVersionCollector{} + + url := cmp.Or(os.Getenv("OPA_TELEMETRY_SERVICE_URL"), ExternalServiceURL) restConfig := fmt.Appendf(nil, `{ "url": %q, @@ -99,21 +103,11 @@ func New(id string, opts Options) (*Reporter, error) { // SendReport sends the telemetry report which includes information such as the OPA version, current memory usage to // the external service -func (r *Reporter) SendReport(ctx context.Context) (*DataResponse, error) { +func (r *GHVersionCollector) SendReport(ctx context.Context) (*DataResponse, error) { rCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - r.gatherersMtx.Lock() - defer r.gatherersMtx.Unlock() - for key, g := range r.gatherers { - var err error - r.body[key], err = g(rCtx) - if err != nil { - return nil, fmt.Errorf("gather telemetry error for key %s: %w", key, err) - } - } - - resp, err := r.client.WithJSON(r.body).Do(rCtx, "POST", "/v1/version") + resp, err := r.client.Do(rCtx, "GET", fmt.Sprintf("/repos/%s/releases/latest", GHRepo)) if err != nil { return nil, err } @@ -123,12 +117,12 @@ func (r *Reporter) SendReport(ctx context.Context) (*DataResponse, error) { switch resp.StatusCode { case http.StatusOK: if resp.Body != nil { - var result DataResponse + var result GHResponse err := json.NewDecoder(resp.Body).Decode(&result) if err != nil { return nil, err } - return &result, nil + return createDataResponse(result) } return nil, nil default: @@ -136,10 +130,50 @@ func (r *Reporter) SendReport(ctx context.Context) (*DataResponse, error) { } } -func (r *Reporter) RegisterGatherer(key string, f Gatherer) { - r.gatherersMtx.Lock() - r.gatherers[key] = f - r.gatherersMtx.Unlock() +func createDataResponse(ghResp GHResponse) (*DataResponse, error) { + if ghResp.TagName == "" { + return nil, errors.New("server response does not contain tag_name") + } + + v := strings.TrimPrefix(version.Version, "v") + sv, err := semver.NewVersion(v) + if err != nil { + return nil, fmt.Errorf("failed to parse current version %q: %w", v, err) + } + + latestV := strings.TrimPrefix(ghResp.TagName, "v") + latestSV, err := semver.NewVersion(latestV) + if err != nil { + return nil, fmt.Errorf("failed to parse latest version %q: %w", latestV, err) + } + + isLatest := sv.Compare(*latestSV) >= 0 + + // Note: alternatively, we could look through the assets in the GH API response to find a matching asset, + // and use its URL. However, this is not guaranteed to be more robust, and wouldn't use the 'openpolicyagent.org' domain. + downloadLink := fmt.Sprintf("https://openpolicyagent.org/downloads/%v/opa_%v_%v", + ghResp.TagName, runtime.GOOS, runtime.GOARCH) + + if runtime.GOARCH == "arm64" { + downloadLink = fmt.Sprintf("%v_static", downloadLink) + } + + if strings.HasPrefix(runtime.GOOS, "win") { + downloadLink = fmt.Sprintf("%v.exe", downloadLink) + } + + return &DataResponse{ + Latest: ReleaseDetails{ + Download: downloadLink, + ReleaseNotes: ghResp.ReleaseNotes, + LatestRelease: ghResp.TagName, + OPAUpToDate: isLatest, + }, + }, nil +} + +func (*GHVersionCollector) RegisterGatherer(_ string, _ Gatherer) { + // no-op for this implementation } // IsSet returns true if dr is populated. diff --git a/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go b/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go index 814847a12a..4f93a4f127 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go +++ b/vendor/github.com/open-policy-agent/opa/internal/runtime/init/init.go @@ -29,6 +29,7 @@ type InsertAndCompileOptions struct { MaxErrors int EnablePrintStatements bool ParserOptions ast.ParserOptions + BundleActivatorPlugin string } // InsertAndCompileResult contains the output of the operation. @@ -68,6 +69,7 @@ func InsertAndCompile(ctx context.Context, opts InsertAndCompileOptions) (*Inser Bundles: opts.Bundles, ExtraModules: policies, ParserOptions: opts.ParserOptions, + Plugin: opts.BundleActivatorPlugin, } err := bundle.Activate(activation) @@ -122,10 +124,11 @@ func LoadPaths(paths []string, asBundle bool, bvc *bundle.VerificationConfig, skipVerify bool, + bundleLazyLoading bool, processAnnotations bool, caps *ast.Capabilities, fsys fs.FS) (*LoadPathsResult, error) { - return LoadPathsForRegoVersion(ast.RegoV0, paths, filter, asBundle, bvc, skipVerify, processAnnotations, false, caps, fsys) + return LoadPathsForRegoVersion(ast.RegoV0, paths, filter, asBundle, bvc, skipVerify, bundleLazyLoading, processAnnotations, false, caps, fsys) } func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, @@ -134,6 +137,7 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, asBundle bool, bvc *bundle.VerificationConfig, skipVerify bool, + bundleLazyLoading bool, processAnnotations bool, followSymlinks bool, caps *ast.Capabilities, @@ -159,6 +163,7 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, WithFS(fsys). WithBundleVerificationConfig(bvc). WithSkipBundleVerification(skipVerify). + WithBundleLazyLoadingMode(bundleLazyLoading). WithFilter(filter). WithProcessAnnotation(processAnnotations). WithCapabilities(caps). @@ -177,6 +182,7 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion, files, err := loader.NewFileLoader(). WithFS(fsys). + WithBundleLazyLoadingMode(bundleLazyLoading). WithProcessAnnotation(processAnnotations). WithCapabilities(caps). WithRegoVersion(regoVersion). diff --git a/vendor/github.com/open-policy-agent/opa/storage/interface.go b/vendor/github.com/open-policy-agent/opa/storage/interface.go index 0192c459c8..a21b5575e9 100644 --- a/vendor/github.com/open-policy-agent/opa/storage/interface.go +++ b/vendor/github.com/open-policy-agent/opa/storage/interface.go @@ -19,6 +19,9 @@ type Store = v1.Store // generic MakeDir functionality in storage.MakeDir type MakeDirer = v1.MakeDirer +// NonEmptyer allows a store implemention to override NonEmpty()) +type NonEmptyer = v1.NonEmptyer + // TransactionParams describes a new transaction. type TransactionParams = v1.TransactionParams diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go b/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go index fde7e26b34..6a45d0af46 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go @@ -198,6 +198,7 @@ var DefaultBuiltins = [...]*Builtin{ JWTVerifyES256, JWTVerifyES384, JWTVerifyES512, + JWTVerifyEdDSA, JWTVerifyHS256, JWTVerifyHS384, JWTVerifyHS512, @@ -769,7 +770,7 @@ var aggregates = category("aggregates") var Count = &Builtin{ Name: "count", - Description: " Count takes a collection or string and returns the number of elements (or characters) in it.", + Description: "Count takes a collection or string and returns the number of elements (or characters) in it.", Decl: types.NewFunction( types.Args( types.Named("collection", types.NewAny( @@ -926,7 +927,7 @@ var ToNumber = &Builtin{ types.N, types.S, types.B, - types.NewNull(), + types.Nl, )).Description("value to convert"), ), types.Named("num", types.N).Description("the numeric representation of `x`"), @@ -2236,6 +2237,20 @@ var JWTVerifyES512 = &Builtin{ canSkipBctx: false, } +var JWTVerifyEdDSA = &Builtin{ + Name: "io.jwt.verify_eddsa", + Description: "Verifies if an EdDSA JWT signature is valid.", + Decl: types.NewFunction( + types.Args( + types.Named("jwt", types.S).Description("JWT token whose signature is to be verified"), + types.Named("certificate", types.S).Description("PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature"), + ), + types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), + ), + Categories: tokensCat, + canSkipBctx: false, +} + var JWTVerifyHS256 = &Builtin{ Name: "io.jwt.verify_hs256", Description: "Verifies if a HS256 (secret) JWT signature is valid.", @@ -2282,7 +2297,7 @@ var JWTVerifyHS512 = &Builtin{ var JWTDecodeVerify = &Builtin{ Name: "io.jwt.decode_verify", Description: `Verifies a JWT signature under parameterized constraints and decodes the claims if it is valid. -Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384 and PS512.`, +Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, and EdDSA.`, Decl: types.NewFunction( types.Args( types.Named("jwt", types.S).Description("JWT token whose signature is to be verified and whose claims are to be checked"), @@ -2573,6 +2588,7 @@ var CryptoX509ParseKeyPair = &Builtin{ ), canSkipBctx: true, } + var CryptoX509ParseRSAPrivateKey = &Builtin{ Name: "crypto.x509.parse_rsa_private_key", Description: "Returns a JWK for signing a JWT from the given PEM-encoded RSA private key.", @@ -3172,7 +3188,7 @@ var GlobMatch = &Builtin{ types.Named("pattern", types.S).Description("glob pattern"), types.Named("delimiters", types.NewAny( types.NewArray(nil, types.S), - types.NewNull(), + types.Nl, )).Description("glob pattern delimiters, e.g. `[\".\", \":\"]`, defaults to `[\".\"]` if unset. If `delimiters` is `null`, glob match without delimiter."), types.Named("match", types.S).Description("string to match against `pattern`"), ), @@ -3453,7 +3469,7 @@ var CastNull = &Builtin{ Name: "cast_null", Decl: types.NewFunction( types.Args(types.A), - types.NewNull(), + types.Nl, ), deprecated: true, canSkipBctx: true, diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go b/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go index a992505862..8c98c0a9eb 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/capabilities.go @@ -14,6 +14,7 @@ import ( "slices" "sort" "strings" + "sync" "github.com/open-policy-agent/opa/internal/semver" "github.com/open-policy-agent/opa/internal/wasm/sdk/opa/capabilities" @@ -38,14 +39,15 @@ type VersionIndex struct { //go:embed version_index.json var versionIndexBs []byte -var minVersionIndex = func() VersionIndex { +// init only on demand, as JSON unmarshalling comes with some cost, and contributes +// noise to things like pprof stats +var minVersionIndexOnce = sync.OnceValue(func() VersionIndex { var vi VersionIndex - err := json.Unmarshal(versionIndexBs, &vi) - if err != nil { + if err := json.Unmarshal(versionIndexBs, &vi); err != nil { panic(err) } return vi -}() +}) // In the compiler, we used this to check that we're OK working with ref heads. // If this isn't present, we'll fail. This is to ensure that older versions of @@ -57,6 +59,24 @@ const FeatureRegoV1 = "rego_v1" const FeatureRegoV1Import = "rego_v1_import" const FeatureKeywordsInRefs = "keywords_in_refs" +// Features carries the default features supported by this version of OPA. +// Use RegisterFeatures to add to them. +var Features = []string{ + FeatureRegoV1, + FeatureKeywordsInRefs, +} + +// RegisterFeatures lets applications wrapping OPA register features, to be +// included in `ast.CapabilitiesForThisVersion()`. +func RegisterFeatures(fs ...string) { + for i := range fs { + if slices.Contains(Features, fs[i]) { + continue + } + Features = append(Features, fs[i]) + } +} + // Capabilities defines a structure containing data that describes the capabilities // or features supported by a particular version of OPA. type Capabilities struct { @@ -141,10 +161,8 @@ func CapabilitiesForThisVersion(opts ...CapabilitiesOption) *Capabilities { f.FutureKeywords = append(f.FutureKeywords, kw) } - f.Features = []string{ - FeatureRegoV1, - FeatureKeywordsInRefs, - } + f.Features = make([]string, len(Features)) + copy(f.Features, Features) } sort.Strings(f.FutureKeywords) @@ -208,7 +226,6 @@ func LoadCapabilitiesVersions() ([]string, error) { // MinimumCompatibleVersion returns the minimum compatible OPA version based on // the built-ins, features, and keywords in c. func (c *Capabilities) MinimumCompatibleVersion() (string, bool) { - var maxVersion semver.Version // this is the oldest OPA release that includes capabilities @@ -216,6 +233,8 @@ func (c *Capabilities) MinimumCompatibleVersion() (string, bool) { panic("unreachable") } + minVersionIndex := minVersionIndexOnce() + for _, bi := range c.Builtins { v, ok := minVersionIndex.Builtins[bi.Name] if !ok { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/check.go b/vendor/github.com/open-policy-agent/opa/v1/ast/check.go index e3d2051a26..0da7e26514 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/check.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/check.go @@ -310,7 +310,7 @@ func (tc *typeChecker) checkRule(env *TypeEnv, as *AnnotationSet, rule *Rule) { var err error tpe, err = nestedObject(cpy, objPath, typeV) if err != nil { - tc.err([]*Error{NewError(TypeErr, rule.Head.Location, err.Error())}) //nolint:govet + tc.err([]*Error{NewError(TypeErr, rule.Head.Location, "%s", err.Error())}) tpe = nil } } else if typeV != nil { @@ -1318,7 +1318,7 @@ func processAnnotation(ss *SchemaSet, annot *SchemaAnnotation, rule *Rule, allow tpe, err := loadSchema(schema, allowNet) if err != nil { - return nil, NewError(TypeErr, rule.Location, err.Error()) //nolint:govet + return nil, NewError(TypeErr, rule.Location, "%s", err.Error()) } return tpe, nil diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go b/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go index f3ca101735..094e659328 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go @@ -26,7 +26,11 @@ import ( // exiting. const CompileErrorLimitDefault = 10 -var errLimitReached = NewError(CompileErr, nil, "error limit reached") +var ( + errLimitReached = NewError(CompileErr, nil, "error limit reached") + + doubleEq = Equal.Ref() +) // Compiler contains the state of a compilation process. type Compiler struct { @@ -850,7 +854,7 @@ func (c *Compiler) PassesTypeCheckRules(rules []*Rule) Errors { tpe, err := loadSchema(schema, allowNet) if err != nil { - return Errors{NewError(TypeErr, nil, err.Error())} //nolint:govet + return Errors{NewError(TypeErr, nil, "%s", err.Error())} } c.inputType = tpe } @@ -955,8 +959,10 @@ func (c *Compiler) buildRuleIndices() { func (c *Compiler) buildComprehensionIndices() { for _, name := range c.sorted { WalkRules(c.Modules[name], func(r *Rule) bool { - candidates := r.Head.Args.Vars() - candidates.Update(ReservedVars) + candidates := ReservedVars.Copy() + if len(r.Head.Args) > 0 { + candidates.Update(r.Head.Args.Vars()) + } n := buildComprehensionIndices(c.debug, c.GetArity, candidates, c.RewrittenVars, r.Body, c.comprehensionIndices) c.counterAdd(compileStageComprehensionIndexBuild, n) return false @@ -1207,7 +1213,7 @@ func (c *Compiler) checkRuleConflicts() { continue // don't self-conflict } msg := fmt.Sprintf("%v conflicts with rule %v defined at %v", childMod.Package, rule.Head.Ref(), rule.Loc()) - c.err(NewError(TypeErr, mod.Package.Loc(), msg)) //nolint:govet + c.err(NewError(TypeErr, mod.Package.Loc(), "%s", msg)) } } } @@ -1281,7 +1287,9 @@ func (c *Compiler) checkSafetyRuleBodies() { m := c.Modules[name] WalkRules(m, func(r *Rule) bool { safe := ReservedVars.Copy() - safe.Update(r.Head.Args.Vars()) + if len(r.Head.Args) > 0 { + safe.Update(r.Head.Args.Vars()) + } r.Body = c.checkBodySafety(safe, r.Body) return false }) @@ -1310,19 +1318,24 @@ var SafetyCheckVisitorParams = VarVisitorParams{ // checkSafetyRuleHeads ensures that variables appearing in the head of a // rule also appear in the body. func (c *Compiler) checkSafetyRuleHeads() { - for _, name := range c.sorted { - m := c.Modules[name] - WalkRules(m, func(r *Rule) bool { + WalkRules(c.Modules[name], func(r *Rule) bool { safe := r.Body.Vars(SafetyCheckVisitorParams) - safe.Update(r.Head.Args.Vars()) - unsafe := r.Head.Vars().Diff(safe) - for v := range unsafe { - if w, ok := c.RewrittenVars[v]; ok { - v = w - } - if !v.IsGenerated() { - c.err(NewError(UnsafeVarErr, r.Loc(), "var %v is unsafe", v)) + if len(r.Head.Args) > 0 { + safe.Update(r.Head.Args.Vars()) + } + if headMayHaveVars(r.Head) { + vars := r.Head.Vars() + if vars.DiffCount(safe) > 0 { + unsafe := vars.Diff(safe) + for v := range unsafe { + if w, ok := c.RewrittenVars[v]; ok { + v = w + } + if !v.IsGenerated() { + c.err(NewError(UnsafeVarErr, r.Loc(), "var %v is unsafe", v)) + } + } } } return false @@ -1681,6 +1694,31 @@ func (c *Compiler) init() { return } + if defaultModuleLoader != nil { + if c.moduleLoader == nil { + c.moduleLoader = defaultModuleLoader + } else { + first := c.moduleLoader + c.moduleLoader = func(res map[string]*Module) (map[string]*Module, error) { + res0, err := first(res) + if err != nil { + return nil, err + } + res1, err := defaultModuleLoader(res) + if err != nil { + return nil, err + } + // merge res1 into res0, based on module "file" names, to avoid clashes + for k, v := range res1 { + if _, ok := res0[k]; !ok { + res0[k] = v + } + } + return res0, nil + } + } + } + if c.capabilities == nil { c.capabilities = CapabilitiesForThisVersion() } @@ -1701,7 +1739,7 @@ func (c *Compiler) init() { if schema := c.schemaSet.Get(SchemaRootRef); schema != nil { tpe, err := loadSchema(schema, c.capabilities.AllowNet) if err != nil { - c.err(NewError(TypeErr, nil, err.Error())) //nolint:govet + c.err(NewError(TypeErr, nil, "%s", err.Error())) } else { c.inputType = tpe } @@ -1869,7 +1907,7 @@ func (c *Compiler) resolveAllRefs() { WalkRules(mod, func(rule *Rule) bool { err := resolveRefsInRule(globals, rule) if err != nil { - c.err(NewError(CompileErr, rule.Location, err.Error())) //nolint:govet + c.err(NewError(CompileErr, rule.Location, "%s", err.Error())) } return false }) @@ -1894,7 +1932,7 @@ func (c *Compiler) resolveAllRefs() { parsed, err := c.moduleLoader(c.Modules) if err != nil { - c.err(NewError(CompileErr, nil, err.Error())) //nolint:govet + c.err(NewError(CompileErr, nil, "%s", err.Error())) return } @@ -2127,12 +2165,16 @@ func rewritePrintCalls(gen *localVarGenerator, getArity func(Ref) int, globals V safe.Update(globals) args := body[i].Operands() + var vis *VarVisitor for j := range args { - vis := NewVarVisitor().WithParams(SafetyCheckVisitorParams) + vis = vis.ClearOrNew().WithParams(SafetyCheckVisitorParams) vis.Walk(args[j]) - unsafe := vis.Vars().Diff(safe) - for _, v := range unsafe.Sorted() { - errs = append(errs, NewError(CompileErr, args[j].Loc(), "var %v is undeclared", v)) + vars := vis.Vars() + if vars.DiffCount(safe) > 0 { + unsafe := vars.Diff(safe) + for _, v := range unsafe.Sorted() { + errs = append(errs, NewError(CompileErr, args[j].Loc(), "var %v is undeclared", v)) + } } } @@ -2140,17 +2182,17 @@ func rewritePrintCalls(gen *localVarGenerator, getArity func(Ref) int, globals V return false, errs } - arr := NewArray() + terms := make([]*Term, 0, len(args)) for j := range args { x := NewTerm(gen.Generate()).SetLocation(args[j].Loc()) capture := Equality.Expr(x, args[j]).SetLocation(args[j].Loc()) - arr = arr.Append(SetComprehensionTerm(x, NewBody(capture)).SetLocation(args[j].Loc())) + terms = append(terms, SetComprehensionTerm(x, NewBody(capture)).SetLocation(args[j].Loc())) } body.Set(NewExpr([]*Term{ NewTerm(InternalPrint.Ref()).SetLocation(body[i].Loc()), - NewTerm(arr).SetLocation(body[i].Loc()), + ArrayTerm(terms...).SetLocation(body[i].Loc()), }).SetLocation(body[i].Loc()), i) } @@ -2270,8 +2312,7 @@ func (c *Compiler) rewriteRefsInHead() { func (c *Compiler) rewriteEquals() { modified := false for _, name := range c.sorted { - mod := c.Modules[name] - modified = rewriteEquals(mod) || modified + modified = rewriteEquals(c.Modules[name]) || modified } if modified { c.Required.addBuiltinSorted(Equal) @@ -2281,8 +2322,7 @@ func (c *Compiler) rewriteEquals() { func (c *Compiler) rewriteDynamicTerms() { f := newEqualityFactory(c.localvargen) for _, name := range c.sorted { - mod := c.Modules[name] - WalkRules(mod, func(rule *Rule) bool { + WalkRules(c.Modules[name], func(rule *Rule) bool { rule.Body = rewriteDynamics(f, rule.Body) return false }) @@ -2546,19 +2586,21 @@ func createMetadataChain(chain []*AnnotationsRef) (*Term, *Error) { } func (c *Compiler) rewriteLocalVars() { - var assignment bool + args := NewVarVisitor() + argsStack := newLocalDeclaredVars() + for _, name := range c.sorted { mod := c.Modules[name] gen := c.localvargen WalkRules(mod, func(rule *Rule) bool { - argsStack := newLocalDeclaredVars() + args.Clear() + argsStack.Clear() - args := NewVarVisitor() - if c.strict { - args.Walk(rule.Head.Args) + if c.strict && len(rule.Head.Args) > 0 { + args.WalkArgs(rule.Head.Args) } unusedArgs := args.Vars() @@ -2603,45 +2645,51 @@ func (c *Compiler) rewriteLocalVars() { } func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsStack *localDeclaredVars, gen *localVarGenerator) (*localDeclaredVars, Errors) { - // Rewrite assignments contained in head of rule. Assignments can - // occur in rule head if they're inside a comprehension. Note, - // assigned vars in comprehensions in the head will be rewritten - // first to preserve scoping rules. For example: - // - // p = [x | x := 1] { x := 2 } becomes p = [__local0__ | __local0__ = 1] { __local1__ = 2 } - // - // This behaviour is consistent scoping inside the body. For example: - // - // p = xs { x := 2; xs = [x | x := 1] } becomes p = xs { __local0__ = 2; xs = [__local1__ | __local1__ = 1] } - nestedXform := &rewriteNestedHeadVarLocalTransform{ - gen: gen, - RewrittenVars: c.RewrittenVars, - strict: c.strict, - } + onlyScalars := !headMayHaveVars(rule.Head) - NewGenericVisitor(nestedXform.Visit).Walk(rule.Head) + var used VarSet - for _, err := range nestedXform.errs { - c.err(err) - } + if !onlyScalars { + // Rewrite assignments contained in head of rule. Assignments can + // occur in rule head if they're inside a comprehension. Note, + // assigned vars in comprehensions in the head will be rewritten + // first to preserve scoping rules. For example: + // + // p = [x | x := 1] { x := 2 } becomes p = [__local0__ | __local0__ = 1] { __local1__ = 2 } + // + // This behaviour is consistent scoping inside the body. For example: + // + // p = xs { x := 2; xs = [x | x := 1] } becomes p = xs { __local0__ = 2; xs = [__local1__ | __local1__ = 1] } + nestedXform := &rewriteNestedHeadVarLocalTransform{ + gen: gen, + RewrittenVars: c.RewrittenVars, + strict: c.strict, + } - // Rewrite assignments in body. - used := NewVarSet() + NewGenericVisitor(nestedXform.Visit).Walk(rule.Head) - for _, t := range rule.Head.Ref()[1:] { - used.Update(t.Vars()) - } + for _, err := range nestedXform.errs { + c.err(err) + } - if rule.Head.Key != nil { - used.Update(rule.Head.Key.Vars()) - } + // Rewrite assignments in body. + used = NewVarSet() - if rule.Head.Value != nil { - valueVars := rule.Head.Value.Vars() - used.Update(valueVars) - for arg := range unusedArgs { - if valueVars.Contains(arg) { - delete(unusedArgs, arg) + for _, t := range rule.Head.Ref()[1:] { + used.Update(t.Vars()) + } + + if rule.Head.Key != nil { + used.Update(rule.Head.Key.Vars()) + } + + if rule.Head.Value != nil { + valueVars := rule.Head.Value.Vars() + used.Update(valueVars) + for arg := range unusedArgs { + if valueVars.Contains(arg) { + delete(unusedArgs, arg) + } } } } @@ -2656,6 +2704,10 @@ func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsSta rule.Body = body + if onlyScalars { + return stack, errs + } + // Rewrite vars in head that refer to locally declared vars in the body. localXform := rewriteHeadVarLocalTransform{declared: declared} @@ -2676,6 +2728,30 @@ func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsSta return stack, errs } +func headMayHaveVars(head *Head) bool { + if head == nil { + return false + } + for i := range head.Args { + if !IsScalar(head.Args[i].Value) { + return true + } + } + if head.Key != nil && !IsScalar(head.Key.Value) { + return true + } + if head.Value != nil && !IsScalar(head.Value.Value) { + return true + } + ref := head.Ref()[1:] + for i := range ref { + if !IsScalar(ref[i].Value) { + return true + } + } + return false +} + type rewriteNestedHeadVarLocalTransform struct { gen *localVarGenerator errs Errors @@ -2684,9 +2760,7 @@ type rewriteNestedHeadVarLocalTransform struct { } func (xform *rewriteNestedHeadVarLocalTransform) Visit(x any) bool { - if term, ok := x.(*Term); ok { - stop := false stack := newLocalDeclaredVars() @@ -2787,7 +2861,7 @@ func (vis *ruleArgLocalRewriter) Visit(x any) Visitor { Walk(vis, vcpy) return k, vcpy, nil }); err != nil { - vis.errs = append(vis.errs, NewError(CompileErr, t.Location, err.Error())) //nolint:govet + vis.errs = append(vis.errs, NewError(CompileErr, t.Location, "%s", err.Error())) } else { t.Value = cpy } @@ -3163,7 +3237,7 @@ func (ci *ComprehensionIndex) String() string { return fmt.Sprintf("", NewArray(ci.Keys...)) } -func buildComprehensionIndices(dbg debug.Debug, arity func(Ref) int, candidates VarSet, rwVars map[Var]Var, node any, result map[*Term]*ComprehensionIndex) uint64 { +func buildComprehensionIndices(dbg debug.Debug, arity func(Ref) int, candidates VarSet, rwVars map[Var]Var, node Body, result map[*Term]*ComprehensionIndex) uint64 { var n uint64 cpy := candidates.Copy() WalkBodies(node, func(b Body) bool { @@ -3365,7 +3439,6 @@ func (vis *comprehensionIndexNestedCandidateVisitor) Walk(x any) { } func (vis *comprehensionIndexNestedCandidateVisitor) visit(x any) bool { - if vis.found { return true } @@ -3904,22 +3977,27 @@ func (vs unsafeVars) Slice() (result []unsafePair) { // If the body cannot be reordered to ensure safety, the second return value // contains a mapping of expressions to unsafe variables in those expressions. func reorderBodyForSafety(builtins map[string]*Builtin, arity func(Ref) int, globals VarSet, body Body) (Body, unsafeVars) { + vis := varVisitorPool.Get().WithParams(SafetyCheckVisitorParams) + vis.WalkBody(body) - bodyVars := body.Vars(SafetyCheckVisitorParams) - reordered := make(Body, 0, len(body)) - safe := VarSet{} - unsafe := unsafeVars{} + defer varVisitorPool.Put(vis) + + bodyVars := vis.Vars().Copy() + safe := bodyVars.Intersect(globals) + unsafe := make(unsafeVars, len(bodyVars)-len(safe)) for _, e := range body { - for v := range e.Vars(SafetyCheckVisitorParams) { - if globals.Contains(v) { - safe.Add(v) - } else { + vis.Clear().WithParams(SafetyCheckVisitorParams).Walk(e) + for v := range vis.Vars() { + if _, ok := safe[v]; !ok { unsafe.Add(e, v) } } } + reordered := make(Body, 0, len(body)) + output := VarSet{} + for { n := len(reordered) @@ -3928,15 +4006,16 @@ func reorderBodyForSafety(builtins map[string]*Builtin, arity func(Ref) int, glo continue } - ovs := outputVarsForExpr(e, arity, safe) + ovs := outputVarsForExpr(e, arity, safe, output) // check closures: is this expression closing over variables that // haven't been made safe by what's already included in `reordered`? vs := unsafeVarsInClosures(e) cv := vs.Intersect(bodyVars).Diff(globals) - uv := cv.Diff(outputVarsForBody(reordered, arity, safe)) + ob := outputVarsForBody(reordered, arity, safe) - if len(uv) > 0 { + if cv.DiffCount(ob) > 0 { + uv := cv.Diff(ob) if uv.Equal(ovs) { // special case "closure-self" continue } @@ -3965,18 +4044,22 @@ func reorderBodyForSafety(builtins map[string]*Builtin, arity func(Ref) int, glo // Update the globals at each expression to include the variables that could // be closed over. g := globals.Copy() + xform := &bodySafetyTransformer{ + builtins: builtins, + arity: arity, + } + gvis := &GenericVisitor{} for i, e := range reordered { if i > 0 { - g.Update(reordered[i-1].Vars(SafetyCheckVisitorParams)) + vis.Walk(reordered[i-1]) + g.Update(vis.Vars()) + vis.Clear().WithParams(SafetyCheckVisitorParams) } - xform := &bodySafetyTransformer{ - builtins: builtins, - arity: arity, - current: e, - globals: g, - unsafe: unsafe, - } - NewGenericVisitor(xform.Visit).Walk(e) + xform.current = e + xform.globals = g + xform.unsafe = unsafe + gvis.f = xform.Visit + gvis.Walk(e) } return reordered, unsafe @@ -4035,9 +4118,12 @@ func (xform *bodySafetyTransformer) Visit(x any) bool { func (xform *bodySafetyTransformer) reorderComprehensionSafety(tv VarSet, body Body) Body { bv := body.Vars(SafetyCheckVisitorParams) bv.Update(xform.globals) - uv := tv.Diff(bv) - for v := range uv { - xform.unsafe.Add(xform.current, v) + + if tv.DiffCount(bv) > 0 { + uv := tv.Diff(bv) + for v := range uv { + xform.unsafe.Add(xform.current, v) + } } r, u := reorderBodyForSafety(xform.builtins, xform.arity, xform.globals, body) @@ -4070,7 +4156,7 @@ func unsafeVarsInClosures(e *Expr) VarSet { WalkClosures(e, func(x any) bool { vis := &VarVisitor{vars: vs} if ev, ok := x.(*Every); ok { - vis.Walk(ev.Body) + vis.WalkBody(ev.Body) return true } vis.Walk(x) @@ -4088,8 +4174,9 @@ func OutputVarsFromBody(c *Compiler, body Body, safe VarSet) VarSet { func outputVarsForBody(body Body, arity func(Ref) int, safe VarSet) VarSet { o := safe.Copy() + output := VarSet{} for _, e := range body { - o.Update(outputVarsForExpr(e, arity, o)) + o.Update(outputVarsForExpr(e, arity, o, output)) } return o.Diff(safe) } @@ -4098,23 +4185,22 @@ func outputVarsForBody(body Body, arity func(Ref) int, safe VarSet) VarSet { // the given expression. For safety checks this means that they would be // made safe by the expr. func OutputVarsFromExpr(c *Compiler, expr *Expr, safe VarSet) VarSet { - return outputVarsForExpr(expr, c.GetArity, safe) + return outputVarsForExpr(expr, c.GetArity, safe, VarSet{}) } -func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { - +func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet, output VarSet) VarSet { // Negated expressions must be safe. if expr.Negated { return VarSet{} } + var vis *VarVisitor + // With modifier inputs must be safe. for _, with := range expr.With { - vis := NewVarVisitor().WithParams(SafetyCheckVisitorParams) + vis = vis.ClearOrNew().WithParams(SafetyCheckVisitorParams) vis.Walk(with) - vars := vis.Vars() - unsafe := vars.Diff(safe) - if len(unsafe) > 0 { + if vis.Vars().DiffCount(safe) > 0 { return VarSet{} } } @@ -4124,7 +4210,7 @@ func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { return outputVarsForTerms(expr, safe) case []*Term: if expr.IsEquality() { - return outputVarsForExprEq(expr, safe) + return outputVarsForExprEq(expr, safe, output) } operator, ok := terms[0].Value.(Ref) @@ -4137,7 +4223,7 @@ func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { return VarSet{} } - return outputVarsForExprCall(expr, ar, safe, terms) + return outputVarsForExprCall(expr, ar, safe, terms, vis, output) case *Every: return outputVarsForTerms(terms.Domain, safe) default: @@ -4145,22 +4231,26 @@ func outputVarsForExpr(expr *Expr, arity func(Ref) int, safe VarSet) VarSet { } } -func outputVarsForExprEq(expr *Expr, safe VarSet) VarSet { - +func outputVarsForExprEq(expr *Expr, safe VarSet, output VarSet) VarSet { if !validEqAssignArgCount(expr) { return safe } - output := outputVarsForTerms(expr, safe) + output.Update(outputVarsForTerms(expr, safe)) output.Update(safe) output.Update(Unify(output, expr.Operand(0), expr.Operand(1))) - return output.Diff(safe) + diff := output.Diff(safe) + + clear(output) + + return diff } -func outputVarsForExprCall(expr *Expr, arity int, safe VarSet, terms []*Term) VarSet { +func outputVarsForExprCall(expr *Expr, arity int, safe VarSet, terms []*Term, vis *VarVisitor, output VarSet) VarSet { + clear(output) - output := outputVarsForTerms(expr, safe) + output.Update(outputVarsForTerms(expr, safe)) numInputTerms := arity + 1 if numInputTerms >= len(terms) { @@ -4173,16 +4263,16 @@ func outputVarsForExprCall(expr *Expr, arity int, safe VarSet, terms []*Term) Va SkipObjectKeys: true, SkipRefHead: true, } - vis := NewVarVisitor().WithParams(params) - vis.Walk(Args(terms[:numInputTerms])) - unsafe := vis.Vars().Diff(output).Diff(safe) + vis = vis.ClearOrNew().WithParams(params) + vis.WalkArgs(Args(terms[:numInputTerms])) - if len(unsafe) > 0 { + unsafe := vis.Vars().Diff(output).DiffCount(safe) + if unsafe > 0 { return VarSet{} } - vis = NewVarVisitor().WithParams(params) - vis.Walk(Args(terms[numInputTerms:])) + vis = vis.Clear().WithParams(params) + vis.WalkArgs(Args(terms[numInputTerms:])) output.Update(vis.vars) return output } @@ -4197,8 +4287,13 @@ func outputVarsForTerms(expr any, safe VarSet) VarSet { if !isRefSafe(r, safe) { return true } - output.Update(r.OutputVars()) - return false + if !r.IsGround() { + // Avoiding r.OutputVars() here as it won't allow reusing the visitor. + vis := varVisitorPool.Get().WithParams(VarVisitorParams{SkipRefHead: true}) + vis.WalkRef(r) + output.Update(vis.Vars()) + varVisitorPool.Put(vis) + } } return false }) @@ -4231,19 +4326,17 @@ type localVarGenerator struct { } func newLocalVarGeneratorForModuleSet(sorted []string, modules map[string]*Module) *localVarGenerator { - exclude := NewVarSet() - vis := &VarVisitor{vars: exclude} + vis := NewVarVisitor() for _, key := range sorted { vis.Walk(modules[key]) } - return &localVarGenerator{exclude: exclude, next: 0} + return &localVarGenerator{exclude: vis.vars, next: 0} } func newLocalVarGenerator(suffix string, node any) *localVarGenerator { - exclude := NewVarSet() - vis := &VarVisitor{vars: exclude} + vis := NewVarVisitor() vis.Walk(node) - return &localVarGenerator{exclude: exclude, suffix: suffix, next: 0} + return &localVarGenerator{exclude: vis.vars, suffix: suffix, next: 0} } func (l *localVarGenerator) Generate() Var { @@ -4257,20 +4350,17 @@ func (l *localVarGenerator) Generate() Var { } func getGlobals(pkg *Package, rules []Ref, imports []*Import) map[Var]*usedRef { + globals := make(map[Var]*usedRef, len(rules)+len(imports)) - globals := make(map[Var]*usedRef, len(rules)) // NB: might grow bigger with imports - - // Populate globals with exports within the package. for _, ref := range rules { v := ref[0].Value.(Var) globals[v] = &usedRef{ref: pkg.Path.Append(StringTerm(string(v)))} } - // Populate globals with imports. for _, imp := range imports { path := imp.Path.Value.(Ref) if FutureRootDocument.Equal(path[0]) || RegoRootDocument.Equal(path[0]) { - continue // ignore future and rego imports + continue } globals[imp.Name()] = &usedRef{ref: path} } @@ -4635,8 +4725,6 @@ func rewriteComprehensionTerms(f *equalityFactory, node any) (any, error) { }) } -var doubleEq = Equal.Ref() - // rewriteEquals will rewrite exprs under x as unification calls instead of == // calls. For example: // @@ -5055,7 +5143,7 @@ type localDeclaredVars struct { assignment bool } -type varOccurrence int +type varOccurrence uint8 const ( newVar varOccurrence = iota @@ -5067,7 +5155,6 @@ const ( type declaredVarSet struct { vs map[Var]Var - reverse map[Var]Var occurrence map[Var]varOccurrence count map[Var]int } @@ -5075,12 +5162,19 @@ type declaredVarSet struct { func newDeclaredVarSet() *declaredVarSet { return &declaredVarSet{ vs: map[Var]Var{}, - reverse: map[Var]Var{}, occurrence: map[Var]varOccurrence{}, count: map[Var]int{}, } } +func (s *declaredVarSet) clear() *declaredVarSet { + clear(s.vs) + clear(s.occurrence) + clear(s.count) + + return s +} + func newLocalDeclaredVars() *localDeclaredVars { return &localDeclaredVars{ vars: []*declaredVarSet{newDeclaredVarSet()}, @@ -5088,21 +5182,39 @@ func newLocalDeclaredVars() *localDeclaredVars { } } +func (s *localDeclaredVars) Clear() { + var vs *declaredVarSet + if len(s.vars) > 0 { + vs = s.vars[0] + } + + clear(s.vars) + clear(s.rewritten) + + s.vars = s.vars[:0] + + if vs != nil { + s.vars = append(s.vars, vs.clear()) + } + if s.vars[0] == nil { + s.vars[0] = newDeclaredVarSet() + } + s.assignment = false +} + func (s *localDeclaredVars) Copy() *localDeclaredVars { stack := &localDeclaredVars{ - vars: []*declaredVarSet{}, - rewritten: map[Var]Var{}, + vars: make([]*declaredVarSet, 0, len(s.vars)), } for i := range s.vars { stack.vars = append(stack.vars, newDeclaredVarSet()) maps.Copy(stack.vars[0].vs, s.vars[i].vs) - maps.Copy(stack.vars[0].reverse, s.vars[i].reverse) maps.Copy(stack.vars[0].occurrence, s.vars[i].occurrence) maps.Copy(stack.vars[0].count, s.vars[i].count) } - maps.Copy(stack.rewritten, s.rewritten) + stack.rewritten = maps.Clone(s.rewritten) return stack } @@ -5125,7 +5237,6 @@ func (s localDeclaredVars) Peek() *declaredVarSet { func (s localDeclaredVars) Insert(x, y Var, occurrence varOccurrence) { elem := s.vars[len(s.vars)-1] elem.vs[x] = y - elem.reverse[y] = x elem.occurrence[x] = occurrence elem.count[x] = 1 @@ -5205,7 +5316,6 @@ func rewriteLocalVars(g *localVarGenerator, stack *localDeclaredVars, used VarSe } func rewriteDeclaredVarsInBody(g *localVarGenerator, stack *localDeclaredVars, used VarSet, body Body, errs Errors, strict bool) (Body, Errors) { - var cpy Body for i := range body { @@ -5238,12 +5348,22 @@ func rewriteDeclaredVarsInBody(g *localVarGenerator, stack *localDeclaredVars, u } func checkUnusedAssignedVars(body Body, stack *localDeclaredVars, used VarSet, errs Errors, strict bool) Errors { - if !strict || len(errs) > 0 { return errs } dvs := stack.Peek() + + hasAssignedVars := false + for _, occ := range dvs.occurrence { + if occ == assignedVar { + hasAssignedVars = true + } + } + if !hasAssignedVars { + return errs + } + unused := NewVarSet() for v, occ := range dvs.occurrence { @@ -5264,18 +5384,26 @@ func checkUnusedAssignedVars(body Body, stack *localDeclaredVars, used VarSet, e } unused = unused.Diff(rewrittenUsed) + if len(unused) == 0 { + return errs + } + + reversed := make(map[Var]Var, len(dvs.vs)) + for k, v := range dvs.vs { + reversed[v] = k + } for _, gv := range unused.Sorted() { found := false for i := range body { if body[i].Vars(VarVisitorParams{}).Contains(gv) { - errs = append(errs, NewError(CompileErr, body[i].Loc(), "assigned var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[i].Loc(), "assigned var %v unused", reversed[gv])) found = true break } } if !found { - errs = append(errs, NewError(CompileErr, body[0].Loc(), "assigned var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[0].Loc(), "assigned var %v unused", reversed[gv])) } } @@ -5291,6 +5419,17 @@ func checkUnusedDeclaredVars(body Body, stack *localDeclaredVars, used VarSet, c } dvs := stack.Peek() + + hasDeclaredVars := false + for _, occ := range dvs.occurrence { + if occ == declaredVar { + hasDeclaredVars = true + } + } + if !hasDeclaredVars { + return errs + } + declared := NewVarSet() for v, occ := range dvs.occurrence { @@ -5309,27 +5448,35 @@ func checkUnusedDeclaredVars(body Body, stack *localDeclaredVars, used VarSet, c } } - unused := declared.Diff(bodyvars).Diff(used) + dbv := declared.Diff(bodyvars) + if dbv.DiffCount(used) == 0 { + return errs + } - for _, gv := range unused.Sorted() { - rv := dvs.reverse[gv] + reversed := make(map[Var]Var, len(dvs.vs)) + for k, v := range dvs.vs { + reversed[v] = k + } + + for _, gv := range dbv.Diff(used).Sorted() { + rv := reversed[gv] if !rv.IsGenerated() { // Scan through body exprs, looking for a match between the // bad var's original name, and each expr's declared vars. foundUnusedVarByName := false for i := range body { varsDeclaredInExpr := declaredVars(body[i]) - if varsDeclaredInExpr.Contains(dvs.reverse[gv]) { + if varsDeclaredInExpr.Contains(rv) { // TODO(philipc): Clean up the offset logic here when the parser // reports more accurate locations. - errs = append(errs, NewError(CompileErr, body[i].Loc(), "declared var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[i].Loc(), "declared var %v unused", rv)) foundUnusedVarByName = true break } } // Default error location returned. if !foundUnusedVarByName { - errs = append(errs, NewError(CompileErr, body[0].Loc(), "declared var %v unused", dvs.reverse[gv])) + errs = append(errs, NewError(CompileErr, body[0].Loc(), "declared var %v unused", rv)) } } } @@ -5351,7 +5498,7 @@ func rewriteEveryStatement(g *localVarGenerator, stack *localDeclaredVars, expr if v := every.Key.Value.(Var); !v.IsWildcard() { gv, err := rewriteDeclaredVar(g, stack, v, declaredVar) if err != nil { - return nil, append(errs, NewError(CompileErr, every.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, every.Loc(), "%s", err.Error())) } every.Key.Value = gv } @@ -5363,7 +5510,7 @@ func rewriteEveryStatement(g *localVarGenerator, stack *localDeclaredVars, expr if v := every.Value.Value.(Var); !v.IsWildcard() { gv, err := rewriteDeclaredVar(g, stack, v, declaredVar) if err != nil { - return nil, append(errs, NewError(CompileErr, every.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, every.Loc(), "%s", err.Error())) } every.Value.Value = gv } @@ -5381,7 +5528,7 @@ func rewriteSomeDeclStatement(g *localVarGenerator, stack *localDeclaredVars, ex switch v := decl.Symbols[i].Value.(type) { case Var: if _, err := rewriteDeclaredVar(g, stack, v, declaredVar); err != nil { - return nil, append(errs, NewError(CompileErr, decl.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, decl.Loc(), "%s", err.Error())) } case Call: var key, val, container *Term @@ -5407,9 +5554,11 @@ func rewriteSomeDeclStatement(g *localVarGenerator, stack *localDeclaredVars, ex RefTerm(VarTerm(Equality.Name)), val, rhs, } - for _, v0 := range outputVarsForExprEq(e, container.Vars()).Sorted() { + output := VarSet{} + + for _, v0 := range outputVarsForExprEq(e, container.Vars(), output).Sorted() { if _, err := rewriteDeclaredVar(g, stack, v0, declaredVar); err != nil { - return nil, append(errs, NewError(CompileErr, decl.Loc(), err.Error())) //nolint:govet + return nil, append(errs, NewError(CompileErr, decl.Loc(), "%s", err.Error())) } } return rewriteDeclaredVarsInExpr(g, stack, e, errs, strict) @@ -5463,7 +5612,7 @@ func rewriteDeclaredAssignment(g *localVarGenerator, stack *localDeclaredVars, e switch v := t.Value.(type) { case Var: if gv, err := rewriteDeclaredVar(g, stack, v, assignedVar); err != nil { - errs = append(errs, NewError(CompileErr, t.Location, err.Error())) //nolint:govet + errs = append(errs, NewError(CompileErr, t.Location, "%s", err.Error())) } else { t.Value = gv } @@ -5478,7 +5627,7 @@ func rewriteDeclaredAssignment(g *localVarGenerator, stack *localDeclaredVars, e case Ref: if RootDocumentRefs.Contains(t) { if gv, err := rewriteDeclaredVar(g, stack, v[0].Value.(Var), assignedVar); err != nil { - errs = append(errs, NewError(CompileErr, t.Location, err.Error())) //nolint:govet + errs = append(errs, NewError(CompileErr, t.Location, "%s", err.Error())) } else { t.Value = gv } @@ -5845,7 +5994,6 @@ func isVirtual(node *TreeNode, ref Ref) bool { } func safetyErrorSlice(unsafe unsafeVars, rewritten map[Var]Var) (result Errors) { - if len(unsafe) == 0 { return } @@ -5897,7 +6045,7 @@ func safetyErrorSlice(unsafe unsafeVars, rewritten map[Var]Var) (result Errors) } func checkUnsafeBuiltins(unsafeBuiltinsMap map[string]struct{}, node any) Errors { - errs := make(Errors, 0) + var errs Errors WalkExprs(node, func(x *Expr) bool { if x.IsCall() { operator := x.Operator().String() diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/default_module_loader.go b/vendor/github.com/open-policy-agent/opa/v1/ast/default_module_loader.go new file mode 100644 index 0000000000..528c253e16 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/default_module_loader.go @@ -0,0 +1,14 @@ +// Copyright 2025 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package ast + +var defaultModuleLoader ModuleLoader + +// DefaultModuleLoader lets you inject an `ast.ModuleLoader` that will +// always be used. If another one is provided with the ast package, +// they will both be consulted to enrich the set of modules dynamically. +func DefaultModuleLoader(ml ModuleLoader) { + defaultModuleLoader = ml +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go b/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go index e5837d678c..d897952eae 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go @@ -2343,7 +2343,7 @@ func (p *Parser) genwildcard() string { } func (p *Parser) error(loc *location.Location, reason string) { - p.errorf(loc, reason) //nolint:govet + p.errorf(loc, "%s", reason) } func (p *Parser) errorf(loc *location.Location, f string, a ...any) { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go b/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go index 42b0503690..f3d4e0d188 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/parser_ext.go @@ -687,7 +687,7 @@ func parseModule(filename string, stmts []Statement, comments []*Comment, regoCo case Body: rule, err := ParseRuleFromBody(mod, stmt) if err != nil { - errs = append(errs, NewError(ParseErr, stmt[0].Location, err.Error())) //nolint:govet + errs = append(errs, NewError(ParseErr, stmt[0].Location, "%s", err.Error())) continue } rule.generatedBody = true diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go b/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go index fd669f1e78..62c82f51ec 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go @@ -1050,10 +1050,10 @@ func (head *Head) MarshalJSON() ([]byte, error) { // Vars returns a set of vars found in the head. func (head *Head) Vars() VarSet { - vis := &VarVisitor{vars: VarSet{}} + vis := NewVarVisitor() // TODO: improve test coverage for this. if head.Args != nil { - vis.Walk(head.Args) + vis.WalkArgs(head.Args) } if head.Key != nil { vis.Walk(head.Key) @@ -1062,7 +1062,7 @@ func (head *Head) Vars() VarSet { vis.Walk(head.Value) } if len(head.Reference) > 0 { - vis.Walk(head.Reference[1:]) + vis.WalkRef(head.Reference[1:]) } return vis.vars } @@ -1119,8 +1119,8 @@ func (a Args) SetLoc(loc *Location) { // Vars returns a set of vars that appear in a. func (a Args) Vars() VarSet { - vis := &VarVisitor{vars: VarSet{}} - vis.Walk(a) + vis := NewVarVisitor() + vis.WalkArgs(a) return vis.vars } @@ -1243,7 +1243,7 @@ func (body Body) String() string { // control which vars are included. func (body Body) Vars(params VarVisitorParams) VarSet { vis := NewVarVisitor().WithParams(params) - vis.Walk(body) + vis.WalkBody(body) return vis.Vars() } @@ -1763,7 +1763,7 @@ func (q *Every) Compare(other *Every) int { // KeyValueVars returns the key and val arguments of an `every` // expression, if they are non-nil and not wildcards. func (q *Every) KeyValueVars() VarSet { - vis := &VarVisitor{vars: VarSet{}} + vis := NewVarVisitor() if q.Key != nil { vis.Walk(q.Key) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/rego_compiler.go b/vendor/github.com/open-policy-agent/opa/v1/ast/rego_compiler.go new file mode 100644 index 0000000000..78d0efc59a --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/rego_compiler.go @@ -0,0 +1,17 @@ +package ast + +import "context" + +type regoCompileCtx struct{} + +func WithCompiler(ctx context.Context, c *Compiler) context.Context { + return context.WithValue(ctx, regoCompileCtx{}, c) +} + +func CompilerFromContext(ctx context.Context) (*Compiler, bool) { + if ctx == nil { + return nil, false + } + v, ok := ctx.Value(regoCompileCtx{}).(*Compiler) + return v, ok +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go b/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go index cb150d39b5..82977c836b 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/syncpools.go @@ -17,6 +17,10 @@ type indexResultPool struct { pool sync.Pool } +type vvPool struct { + pool sync.Pool +} + func (p *termPtrPool) Get() *Term { return p.pool.Get().(*Term) } @@ -44,6 +48,17 @@ func (p *indexResultPool) Put(x *IndexResult) { } } +func (p *vvPool) Get() *VarVisitor { + return p.pool.Get().(*VarVisitor) +} + +func (p *vvPool) Put(vv *VarVisitor) { + if vv != nil { + vv.Clear() + p.pool.Put(vv) + } +} + var TermPtrPool = &termPtrPool{ pool: sync.Pool{ New: func() any { @@ -60,6 +75,14 @@ var sbPool = &stringBuilderPool{ }, } +var varVisitorPool = &vvPool{ + pool: sync.Pool{ + New: func() any { + return NewVarVisitor() + }, + }, +} + var IndexResultPool = &indexResultPool{ pool: sync.Pool{ New: func() any { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/term.go b/vendor/github.com/open-policy-agent/opa/v1/ast/term.go index 6b21e3f53c..32d294f3ce 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/term.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/term.go @@ -452,7 +452,7 @@ func (term *Term) UnmarshalJSON(bs []byte) error { // Vars returns a VarSet with variables contained in this term. func (term *Term) Vars() VarSet { - vis := &VarVisitor{vars: VarSet{}} + vis := NewVarVisitor() vis.Walk(term) return vis.vars } @@ -674,6 +674,9 @@ func FloatNumberTerm(f float64) *Term { func (num Number) Equal(other Value) bool { switch other := other.(type) { case Number: + if num == other { + return true + } if n1, ok1 := num.Int64(); ok1 { n2, ok2 := other.Int64() if ok1 && ok2 { @@ -718,6 +721,11 @@ func (num Number) Find(path Ref) (Value, error) { // Hash returns the hash code for the Value. func (num Number) Hash() int { + if len(num) < 4 { + if i, err := strconv.Atoi(string(num)); err == nil { + return i + } + } f, err := json.Number(num).Float64() if err != nil { bs := []byte(num) @@ -1227,7 +1235,7 @@ func (ref Ref) String() string { // this expression in isolation. func (ref Ref) OutputVars() VarSet { vis := NewVarVisitor().WithParams(VarVisitorParams{SkipRefHead: true}) - vis.Walk(ref) + vis.WalkRef(ref) return vis.Vars() } @@ -1331,10 +1339,7 @@ func (arr *Array) Find(path Ref) (Value, error) { return nil, errFindNotFound } i, ok := num.Int() - if !ok { - return nil, errFindNotFound - } - if i < 0 || i >= arr.Len() { + if !ok || i < 0 || i >= arr.Len() { return nil, errFindNotFound } @@ -1355,12 +1360,7 @@ func (arr *Array) Get(pos *Term) *Term { return nil } - i, ok := num.Int() - if !ok { - return nil - } - - if i >= 0 && i < len(arr.elems) { + if i, ok := num.Int(); ok && i >= 0 && i < len(arr.elems) { return arr.elems[i] } @@ -2194,24 +2194,21 @@ func (l *lazyObj) Find(path Ref) (Value, error) { } type object struct { - elems map[int]*objectElem - keys objectElemSlice - ground int // number of key and value grounds. Counting is - // required to support insert's key-value replace. + elems map[int]*objectElem + keys []*objectElem + ground int // number of key and value grounds. Counting is required to support insert's key-value replace. hash int sortGuard sync.Once // Prevents race condition around sorting. } func newobject(n int) *object { - var keys objectElemSlice + var keys []*objectElem if n > 0 { - keys = make(objectElemSlice, 0, n) + keys = make([]*objectElem, 0, n) } return &object{ elems: make(map[int]*objectElem, n), keys: keys, - ground: 0, - hash: 0, sortGuard: sync.Once{}, } } @@ -2222,19 +2219,13 @@ type objectElem struct { next *objectElem } -type objectElemSlice []*objectElem - -func (s objectElemSlice) Less(i, j int) bool { return Compare(s[i].key.Value, s[j].key.Value) < 0 } -func (s objectElemSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s objectElemSlice) Len() int { return len(s) } - // Item is a helper for constructing an tuple containing two Terms // representing a key/value pair in an Object. func Item(key, value *Term) [2]*Term { return [2]*Term{key, value} } -func (obj *object) sortedKeys() objectElemSlice { +func (obj *object) sortedKeys() []*objectElem { obj.sortGuard.Do(func() { slices.SortFunc(obj.keys, func(a, b *objectElem) int { return a.key.Value.Compare(b.key.Value) @@ -2540,6 +2531,9 @@ func (obj *object) get(k *Term) *objectElem { case Number: if xi, ok := x.Int64(); ok { equal = func(y Value) bool { + if x == y { + return true + } if y, ok := y.(Number); ok { if yi, ok := y.Int64(); ok { return xi == yi @@ -2630,6 +2624,9 @@ func (obj *object) insert(k, v *Term, resetSortGuard bool) { case Number: if xi, err := json.Number(x).Int64(); err == nil { equal = func(y Value) bool { + if x == y { + return true + } if y, ok := y.(Number); ok { if yi, err := json.Number(y).Int64(); err == nil { return xi == yi @@ -2697,10 +2694,6 @@ func (obj *object) insert(k, v *Term, resetSortGuard bool) { for curr := head; curr != nil; curr = curr.next { if equal(curr.key.Value) { - // The ground bit of the value may change in - // replace, hence adjust the counter per old - // and new value. - if curr.value.IsGround() { obj.ground-- } @@ -2708,20 +2701,21 @@ func (obj *object) insert(k, v *Term, resetSortGuard bool) { obj.ground++ } + // Update hash based on the new value curr.value = v + obj.elems[hash] = curr + obj.hash = 0 + for ehash := range obj.elems { + obj.hash += ehash + obj.elems[ehash].value.Hash() + } - obj.rehash() return } } - elem := &objectElem{ - key: k, - value: v, - next: head, - } - obj.elems[hash] = elem + + obj.elems[hash] = &objectElem{key: k, value: v, next: head} // O(1) insertion, but we'll have to re-sort the keys later. - obj.keys = append(obj.keys, elem) + obj.keys = append(obj.keys, obj.elems[hash]) if resetSortGuard { // Reset the sync.Once instance. @@ -2742,19 +2736,6 @@ func (obj *object) insert(k, v *Term, resetSortGuard bool) { } } -func (obj *object) rehash() { - // obj.keys is considered truth, from which obj.hash and obj.elems are recalculated. - - obj.hash = 0 - obj.elems = make(map[int]*objectElem, len(obj.keys)) - - for _, elem := range obj.keys { - hash := elem.key.Hash() - obj.hash += hash + elem.value.Hash() - obj.elems[hash] = elem - } -} - func filterObject(o Value, filter Value) (Value, error) { if (Null{}).Equal(filter) { return o, nil diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go b/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go index 3af52815f7..acbe275c0f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/unify.go @@ -21,10 +21,12 @@ func isRefSafe(ref Ref, safe VarSet) bool { } func isCallSafe(call Call, safe VarSet) bool { - vis := NewVarVisitor().WithParams(SafetyCheckVisitorParams) + vis := varVisitorPool.Get().WithParams(SafetyCheckVisitorParams) vis.Walk(call) - unsafe := vis.Vars().Diff(safe) - return len(unsafe) == 0 + isSafe := vis.Vars().DiffCount(safe) == 0 + varVisitorPool.Put(vis) + + return isSafe } // Unify returns a set of variables that will be unified when the equality expression defined by @@ -173,11 +175,16 @@ func (u *unifier) unify(a *Term, b *Term) { } func (u *unifier) markAllSafe(x Value) { - vis := u.varVisitor() + vis := varVisitorPool.Get().WithParams(VarVisitorParams{ + SkipRefHead: true, + SkipObjectKeys: true, + SkipClosures: true, + }) vis.Walk(x) for v := range vis.Vars() { u.markSafe(v) } + varVisitorPool.Put(vis) } func (u *unifier) markSafe(x Var) { @@ -204,16 +211,21 @@ func (u *unifier) markSafe(x Var) { func (u *unifier) markUnknown(a, b Var) { if _, ok := u.unknown[a]; !ok { - u.unknown[a] = NewVarSet() + u.unknown[a] = NewVarSet(b) + } else { + u.unknown[a].Add(b) } - u.unknown[a].Add(b) } func (u *unifier) unifyAll(a Var, b Value) { if u.isSafe(a) { u.markAllSafe(b) } else { - vis := u.varVisitor() + vis := varVisitorPool.Get().WithParams(VarVisitorParams{ + SkipRefHead: true, + SkipObjectKeys: true, + SkipClosures: true, + }) vis.Walk(b) unsafe := vis.Vars().Diff(u.safe).Diff(u.unified) if len(unsafe) == 0 { @@ -223,13 +235,6 @@ func (u *unifier) unifyAll(a Var, b Value) { u.markUnknown(a, v) } } + varVisitorPool.Put(vis) } } - -func (*unifier) varVisitor() *VarVisitor { - return NewVarVisitor().WithParams(VarVisitorParams{ - SkipRefHead: true, - SkipObjectKeys: true, - SkipClosures: true, - }) -} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go b/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go index bccb035e30..e5bd52ae8c 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/varset.go @@ -50,13 +50,7 @@ func (s VarSet) Copy() VarSet { // Diff returns a VarSet containing variables in s that are not in vs. func (s VarSet) Diff(vs VarSet) VarSet { - i := 0 - for v := range s { - if !vs.Contains(v) { - i++ - } - } - r := NewVarSetOfSize(i) + r := NewVarSetOfSize(s.DiffCount(vs)) for v := range s { if !vs.Contains(v) { r.Add(v) @@ -65,6 +59,16 @@ func (s VarSet) Diff(vs VarSet) VarSet { return r } +// DiffCount returns the number of variables in s that are not in vs. +func (s VarSet) DiffCount(vs VarSet) (i int) { + for v := range s { + if !vs.Contains(v) { + i++ + } + } + return +} + // Equal returns true if s contains exactly the same elements as vs. func (s VarSet) Equal(vs VarSet) bool { if len(s) != len(vs) { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json b/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json index b84f09a290..b02f785299 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json @@ -539,6 +539,13 @@ "PreRelease": "", "Metadata": "" }, + "io.jwt.verify_eddsa": { + "Major": 1, + "Minor": 8, + "Patch": 0, + "PreRelease": "", + "Metadata": "" + }, "io.jwt.verify_es256": { "Major": 0, "Minor": 17, diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go b/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go index 16567014f4..4ae6569ad7 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/visit.go @@ -563,12 +563,37 @@ func NewVarVisitor() *VarVisitor { } } +// Clear resets the visitor to its initial state, and returns it for chaining. +func (vis *VarVisitor) Clear() *VarVisitor { + vis.params = VarVisitorParams{} + clear(vis.vars) + + return vis +} + +// ClearOrNew returns a new VarVisitor if vis is nil, or else a cleared VarVisitor. +func (vis *VarVisitor) ClearOrNew() *VarVisitor { + if vis == nil { + return NewVarVisitor() + } + return vis.Clear() +} + // WithParams sets the parameters in params on vis. func (vis *VarVisitor) WithParams(params VarVisitorParams) *VarVisitor { vis.params = params return vis } +// Add adds a variable v to the visitor's set of variables. +func (vis *VarVisitor) Add(v Var) { + if vis.vars == nil { + vis.vars = NewVarSet(v) + } else { + vis.vars.Add(v) + } +} + // Vars returns a VarSet that contains collected vars. func (vis *VarVisitor) Vars() VarSet { return vis.vars @@ -661,7 +686,7 @@ func (vis *VarVisitor) visit(v any) bool { } } if v, ok := v.(Var); ok { - vis.vars.Add(v) + vis.Add(v) } return false } @@ -687,58 +712,55 @@ func (vis *VarVisitor) Walk(x any) { vis.Walk(x.Comments[i]) } case *Package: - vis.Walk(x.Path) + vis.WalkRef(x.Path) case *Import: vis.Walk(x.Path) - vis.Walk(x.Alias) + if x.Alias != "" { + vis.Add(x.Alias) + } case *Rule: vis.Walk(x.Head) - vis.Walk(x.Body) + vis.WalkBody(x.Body) if x.Else != nil { vis.Walk(x.Else) } case *Head: if len(x.Reference) > 0 { - vis.Walk(x.Reference) + vis.WalkRef(x.Reference) } else { - vis.Walk(x.Name) + vis.Add(x.Name) if x.Key != nil { vis.Walk(x.Key) } } - vis.Walk(x.Args) - + vis.WalkArgs(x.Args) if x.Value != nil { vis.Walk(x.Value) } case Body: - for i := range x { - vis.Walk(x[i]) - } + vis.WalkBody(x) case Args: - for i := range x { - vis.Walk(x[i]) - } + vis.WalkArgs(x) case *Expr: switch ts := x.Terms.(type) { case *Term, *SomeDecl, *Every: vis.Walk(ts) case []*Term: for i := range ts { - vis.Walk(ts[i]) + vis.Walk(ts[i].Value) } } for i := range x.With { vis.Walk(x.With[i]) } case *With: - vis.Walk(x.Target) - vis.Walk(x.Value) + vis.Walk(x.Target.Value) + vis.Walk(x.Value.Value) case *Term: vis.Walk(x.Value) case Ref: for i := range x { - vis.Walk(x[i]) + vis.Walk(x[i].Value) } case *object: x.Foreach(func(k, _ *Term) { @@ -755,29 +777,56 @@ func (vis *VarVisitor) Walk(x any) { vis.Walk(xSlice[i]) } case *ArrayComprehension: - vis.Walk(x.Term) - vis.Walk(x.Body) + vis.Walk(x.Term.Value) + vis.WalkBody(x.Body) case *ObjectComprehension: - vis.Walk(x.Key) - vis.Walk(x.Value) - vis.Walk(x.Body) + vis.Walk(x.Key.Value) + vis.Walk(x.Value.Value) + vis.WalkBody(x.Body) case *SetComprehension: - vis.Walk(x.Term) - vis.Walk(x.Body) + vis.Walk(x.Term.Value) + vis.WalkBody(x.Body) case Call: for i := range x { - vis.Walk(x[i]) + vis.Walk(x[i].Value) } case *Every: if x.Key != nil { - vis.Walk(x.Key) + vis.Walk(x.Key.Value) } vis.Walk(x.Value) vis.Walk(x.Domain) - vis.Walk(x.Body) + vis.WalkBody(x.Body) case *SomeDecl: for i := range x.Symbols { vis.Walk(x.Symbols[i]) } } } + +// WalkArgs exists only to avoid the allocation cost of boxing Args to `any` in the VarVisitor. +// Use it when you know beforehand that the type to walk is Args. +func (vis *VarVisitor) WalkArgs(x Args) { + for i := range x { + vis.Walk(x[i].Value) + } +} + +// WalkRef exists only to avoid the allocation cost of boxing Ref to `any` in the VarVisitor. +// Use it when you know beforehand that the type to walk is a Ref. +func (vis *VarVisitor) WalkRef(ref Ref) { + if vis.params.SkipRefHead { + ref = ref[1:] + } + for _, term := range ref { + vis.Walk(term.Value) + } +} + +// WalkBody exists only to avoid the allocation cost of boxing Body to `any` in the VarVisitor. +// Use it when you know beforehand that the type to walk is a Body. +func (vis *VarVisitor) WalkBody(body Body) { + for _, expr := range body { + vis.Walk(expr) + } +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go index 10519eb9c4..5b418c360b 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go @@ -21,6 +21,7 @@ import ( "path/filepath" "reflect" "strings" + "sync" "github.com/gobwas/glob" "github.com/open-policy-agent/opa/internal/file/archive" @@ -29,6 +30,7 @@ import ( astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/format" "github.com/open-policy-agent/opa/v1/metrics" + "github.com/open-policy-agent/opa/v1/storage" "github.com/open-policy-agent/opa/v1/util" ) @@ -435,6 +437,45 @@ type PlanModuleFile struct { Raw []byte } +var ( + pluginMtx sync.Mutex + + // The bundle activator to use by default. + bundleExtActivator string + + // The function to use for creating a storage.Store for bundles. + BundleExtStore func() storage.Store +) + +// RegisterDefaultBundleActivator sets the default bundle activator for OPA to use for bundle activation. +// The id must already have been registered with RegisterActivator. +func RegisterDefaultBundleActivator(id string) { + pluginMtx.Lock() + defer pluginMtx.Unlock() + + bundleExtActivator = id +} + +// RegisterStoreFunc sets the function to use for creating storage for bundles +// in OPA. If no function is registered, OPA will use situational defaults to +// decide on what sort of storage.Store to create when bundle storage is +// needed. Typically the default is inmem.Store. +func RegisterStoreFunc(s func() storage.Store) { + pluginMtx.Lock() + defer pluginMtx.Unlock() + + BundleExtStore = s +} + +// HasExtension returns true if a default bundle activator has been set +// with RegisterDefaultBundleActivator. +func HasExtension() bool { + pluginMtx.Lock() + defer pluginMtx.Unlock() + + return bundleExtActivator != "" +} + // Reader contains the reader to load the bundle from. type Reader struct { loader DirectoryLoader @@ -464,10 +505,11 @@ func NewReader(r io.Reader) *Reader { // specified DirectoryLoader. func NewCustomReader(loader DirectoryLoader) *Reader { nr := Reader{ - loader: loader, - metrics: metrics.New(), - files: make(map[string]FileInfo), - sizeLimitBytes: DefaultSizeLimitBytes + 1, + loader: loader, + metrics: metrics.New(), + files: make(map[string]FileInfo), + sizeLimitBytes: DefaultSizeLimitBytes + 1, + lazyLoadingMode: HasExtension(), } return &nr } @@ -721,7 +763,7 @@ func (r *Reader) Read() (Bundle, error) { modulePopts.RegoVersion = regoVersion } r.metrics.Timer(metrics.RegoModuleParse).Start() - mf.Parsed, err = ast.ParseModuleWithOpts(mf.Path, string(mf.Raw), modulePopts) + mf.Parsed, err = ast.ParseModuleWithOpts(mf.Path, util.ByteSliceToString(mf.Raw), modulePopts) r.metrics.Timer(metrics.RegoModuleParse).Stop() if err != nil { return bundle, err diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go index dbd8ff2697..f16fe37fc7 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/keys.go @@ -6,12 +6,14 @@ package bundle import ( + "crypto/x509" "encoding/pem" + "errors" "fmt" "os" + "strings" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" + "github.com/lestrrat-go/jwx/v3/jwa" "github.com/open-policy-agent/opa/v1/keys" "github.com/open-policy-agent/opa/v1/util" @@ -106,26 +108,53 @@ func (s *SigningConfig) WithPlugin(plugin string) *SigningConfig { // GetPrivateKey returns the private key or secret from the signing config func (s *SigningConfig) GetPrivateKey() (any, error) { + var keyData string - block, _ := pem.Decode([]byte(s.Key)) - if block != nil { - return sign.GetSigningKey(s.Key, jwa.SignatureAlgorithm(s.Algorithm)) + alg, ok := jwa.LookupSignatureAlgorithm(s.Algorithm) + if !ok { + return nil, fmt.Errorf("unknown signature algorithm: %s", s.Algorithm) } - var priv string - if _, err := os.Stat(s.Key); err == nil { - bs, err := os.ReadFile(s.Key) - if err != nil { + // Check if the key looks like PEM data first (starts with -----BEGIN) + if strings.HasPrefix(s.Key, "-----BEGIN") { + keyData = s.Key + } else { + // Try to read as a file path + if _, err := os.Stat(s.Key); err == nil { + bs, err := os.ReadFile(s.Key) + if err != nil { + return nil, err + } + keyData = string(bs) + } else if os.IsNotExist(err) { + // Not a file, treat as raw key data + keyData = s.Key + } else { return nil, err } - priv = string(bs) - } else if os.IsNotExist(err) { - priv = s.Key - } else { - return nil, err } - return sign.GetSigningKey(priv, jwa.SignatureAlgorithm(s.Algorithm)) + // For HMAC algorithms, return the key as bytes + if alg == jwa.HS256() || alg == jwa.HS384() || alg == jwa.HS512() { + return []byte(keyData), nil + } + + // For RSA/ECDSA algorithms, parse the PEM-encoded key + block, _ := pem.Decode([]byte(keyData)) + if block == nil { + return nil, errors.New("failed to parse PEM block containing the key") + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + default: + return nil, fmt.Errorf("unsupported key type: %s", block.Type) + } } // GetClaims returns the claims by reading the file specified in the signing config diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go index edc41a1e50..30640731ef 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/sign.go @@ -6,13 +6,11 @@ package bundle import ( - "crypto/rand" - "encoding/json" "fmt" - "maps" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jwt" ) const defaultSignerID = "_default" @@ -51,7 +49,7 @@ type DefaultSigner struct{} // included in the payload and the bundle signing config. The keyID if non-empty, // represents the value for the "keyid" claim in the token func (*DefaultSigner) GenerateSignedToken(files []FileInfo, sc *SigningConfig, keyID string) (string, error) { - payload, err := generatePayload(files, sc, keyID) + token, err := generateToken(files, sc, keyID) if err != nil { return "", err } @@ -61,37 +59,35 @@ func (*DefaultSigner) GenerateSignedToken(files []FileInfo, sc *SigningConfig, k return "", err } - var headers jws.StandardHeaders - - if err := headers.Set(jws.AlgorithmKey, jwa.SignatureAlgorithm(sc.Algorithm)); err != nil { - return "", err + // Parse the algorithm string to jwa.SignatureAlgorithm + alg, ok := jwa.LookupSignatureAlgorithm(sc.Algorithm) + if !ok { + return "", fmt.Errorf("unknown signature algorithm: %s", sc.Algorithm) } - if keyID != "" { - if err := headers.Set(jws.KeyIDKey, keyID); err != nil { - return "", err - } + // In order to sign the token with a kid, we need a key ID _on_ the key + // (note: we might be able to make this more efficient if we just load + // the key as a JWK from the start) + jwkKey, err := jwk.Import(privateKey) + if err != nil { + return "", fmt.Errorf("failed to import private key: %w", err) + } + if err := jwkKey.Set(jwk.KeyIDKey, keyID); err != nil { + return "", fmt.Errorf("failed to set key ID on JWK: %w", err) } - hdr, err := json.Marshal(headers) + // Since v3.0.6, jwx will take the fast path for signing the token if + // there's exactly one WithKey in the options with no sub-options + signed, err := jwt.Sign(token, jwt.WithKey(alg, jwkKey)) if err != nil { return "", err } - - token, err := jws.SignLiteral(payload, - jwa.SignatureAlgorithm(sc.Algorithm), - privateKey, - hdr, - rand.Reader) - if err != nil { - return "", err - } - return string(token), nil + return string(signed), nil } -func generatePayload(files []FileInfo, sc *SigningConfig, keyID string) ([]byte, error) { - payload := make(map[string]any) - payload["files"] = files +func generateToken(files []FileInfo, sc *SigningConfig, keyID string) (jwt.Token, error) { + tb := jwt.NewBuilder() + tb.Claim("files", files) if sc.ClaimsPath != "" { claims, err := sc.GetClaims() @@ -99,12 +95,14 @@ func generatePayload(files []FileInfo, sc *SigningConfig, keyID string) ([]byte, return nil, err } - maps.Copy(payload, claims) + for k, v := range claims { + tb.Claim(k, v) + } } else if keyID != "" { // keyid claim is deprecated but include it for backwards compatibility. - payload["keyid"] = keyID + tb.Claim("keyid", keyID) } - return json.Marshal(payload) + return tb.Build() } // GetSigner returns the Signer registered under the given id diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go index 33e6887d84..f203f7086b 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/store.go @@ -12,7 +12,10 @@ import ( "fmt" "maps" "path/filepath" + "slices" + "sort" "strings" + "sync" iCompiler "github.com/open-policy-agent/opa/internal/compiler" "github.com/open-policy-agent/opa/internal/json/patch" @@ -22,6 +25,15 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) +const defaultActivatorID = "_default" + +var ( + activators = map[string]Activator{ + defaultActivatorID: &DefaultActivator{}, + } + activatorMtx sync.Mutex +) + // BundlesBasePath is the storage path used for storing bundle metadata var BundlesBasePath = storage.MustParsePath("/system/bundles") @@ -328,6 +340,11 @@ func readEtagFromStore(ctx context.Context, store storage.Store, txn storage.Tra return str, nil } +// Activator is the interface expected for implementations that activate bundles. +type Activator interface { + Activate(*ActivateOpts) error +} + // ActivateOpts defines options for the Activate API call. type ActivateOpts struct { Ctx context.Context @@ -340,15 +357,39 @@ type ActivateOpts struct { ExtraModules map[string]*ast.Module // Optional AuthorizationDecisionRef ast.Ref ParserOptions ast.ParserOptions + Plugin string legacy bool } +type DefaultActivator struct{} + +func (*DefaultActivator) Activate(opts *ActivateOpts) error { + opts.legacy = false + return activateBundles(opts) +} + // Activate the bundle(s) by loading into the given Store. This will load policies, data, and record // the manifest in storage. The compiler provided will have had the polices compiled on it. func Activate(opts *ActivateOpts) error { - opts.legacy = false - return activateBundles(opts) + plugin := opts.Plugin + + // For backwards compatibility, check if there is no plugin specified, and use default. + if plugin == "" { + // Invoke extension activator if supplied. Otherwise, use default. + if HasExtension() { + plugin = bundleExtActivator + } else { + plugin = defaultActivatorID + } + } + + activator, err := GetActivator(plugin) + if err != nil { + return err + } + + return activator.Activate(opts) } // DeactivateOpts defines options for the Deactivate API call @@ -1020,32 +1061,40 @@ func lookup(path storage.Path, data map[string]any) (any, bool) { return value, ok } -func hasRootsOverlap(ctx context.Context, store storage.Store, txn storage.Transaction, bundles map[string]*Bundle) error { - collisions := map[string][]string{} - allBundles, err := ReadBundleNamesFromStore(ctx, store, txn) +func hasRootsOverlap(ctx context.Context, store storage.Store, txn storage.Transaction, newBundles map[string]*Bundle) error { + storeBundles, err := ReadBundleNamesFromStore(ctx, store, txn) if suppressNotFound(err) != nil { return err } allRoots := map[string][]string{} + bundlesWithEmptyRoots := map[string]bool{} // Build a map of roots for existing bundles already in the system - for _, name := range allBundles { + for _, name := range storeBundles { roots, err := ReadBundleRootsFromStore(ctx, store, txn, name) if suppressNotFound(err) != nil { return err } allRoots[name] = roots + if slices.Contains(roots, "") { + bundlesWithEmptyRoots[name] = true + } } // Add in any bundles that are being activated, overwrite existing roots // with new ones where bundles are in both groups. - for name, bundle := range bundles { + for name, bundle := range newBundles { allRoots[name] = *bundle.Manifest.Roots + if slices.Contains(*bundle.Manifest.Roots, "") { + bundlesWithEmptyRoots[name] = true + } } // Now check for each new bundle if it conflicts with any of the others - for name, bundle := range bundles { + collidingBundles := map[string]bool{} + conflictSet := map[string]bool{} + for name, bundle := range newBundles { for otherBundle, otherRoots := range allRoots { if name == otherBundle { // Skip the current bundle being checked @@ -1055,22 +1104,41 @@ func hasRootsOverlap(ctx context.Context, store storage.Store, txn storage.Trans // Compare the "new" roots with other existing (or a different bundles new roots) for _, newRoot := range *bundle.Manifest.Roots { for _, otherRoot := range otherRoots { - if RootPathsOverlap(newRoot, otherRoot) { - collisions[otherBundle] = append(collisions[otherBundle], newRoot) + if !RootPathsOverlap(newRoot, otherRoot) { + continue + } + + collidingBundles[name] = true + collidingBundles[otherBundle] = true + + // Different message required if the roots are same + if newRoot == otherRoot { + conflictSet[fmt.Sprintf("root %s is in multiple bundles", newRoot)] = true + } else { + paths := []string{newRoot, otherRoot} + sort.Strings(paths) + conflictSet[fmt.Sprintf("%s overlaps %s", paths[0], paths[1])] = true } } } } } - if len(collisions) > 0 { - var bundleNames []string - for name := range collisions { - bundleNames = append(bundleNames, name) - } - return fmt.Errorf("detected overlapping roots in bundle manifest with: %s", bundleNames) + if len(collidingBundles) == 0 { + return nil } - return nil + + bundleNames := strings.Join(util.KeysSorted(collidingBundles), ", ") + + if len(bundlesWithEmptyRoots) > 0 { + return fmt.Errorf( + "bundles [%s] have overlapping roots and cannot be activated simultaneously because bundle(s) [%s] specify empty root paths ('') which overlap with any other bundle root", + bundleNames, + strings.Join(util.KeysSorted(bundlesWithEmptyRoots), ", "), + ) + } + + return fmt.Errorf("detected overlapping roots in manifests for these bundles: [%s] (%s)", bundleNames, strings.Join(util.KeysSorted(conflictSet), ", ")) } func applyPatches(ctx context.Context, store storage.Store, txn storage.Transaction, patches []PatchOperation) error { @@ -1149,3 +1217,29 @@ func ActivateLegacy(opts *ActivateOpts) error { opts.legacy = true return activateBundles(opts) } + +// GetActivator returns the Activator registered under the given id +func GetActivator(id string) (Activator, error) { + activator, ok := activators[id] + + if !ok { + return nil, fmt.Errorf("no activator exists under id %s", id) + } + + return activator, nil +} + +// RegisterActivator registers a bundle Activator under the given id. +// The id value can later be referenced in ActivateOpts.Plugin to specify +// which activator should be used for that bundle activation operation. +// Note: This must be called *before* RegisterDefaultBundleActivator. +func RegisterActivator(id string, a Activator) { + activatorMtx.Lock() + defer activatorMtx.Unlock() + + if id == defaultActivatorID { + panic("cannot use reserved activator id, use a different id") + } + + activators[id] = a +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go index 829e98acdf..82e308b49e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/verify.go @@ -7,18 +7,52 @@ package bundle import ( "bytes" + "crypto/x509" "encoding/base64" "encoding/hex" "encoding/json" + "encoding/pem" "errors" "fmt" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws" - "github.com/open-policy-agent/opa/internal/jwx/jws/verify" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" "github.com/open-policy-agent/opa/v1/util" ) +// parseVerificationKey converts a string key to the appropriate type for jws.Verify +func parseVerificationKey(keyData string, alg jwa.SignatureAlgorithm) (any, error) { + // For HMAC algorithms, return the key as bytes + if alg == jwa.HS256() || alg == jwa.HS384() || alg == jwa.HS512() { + return []byte(keyData), nil + } + + // For RSA/ECDSA algorithms, try to parse as PEM first + block, _ := pem.Decode([]byte(keyData)) + if block != nil { + switch block.Type { + case "RSA PUBLIC KEY": + return x509.ParsePKCS1PublicKey(block.Bytes) + case "PUBLIC KEY": + return x509.ParsePKIXPublicKey(block.Bytes) + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + case "CERTIFICATE": + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + return cert.PublicKey, nil + } + } + + return nil, errors.New("failed to parse PEM block containing the key") +} + const defaultVerifierID = "_default" var verifiers map[string]Verifier @@ -82,26 +116,42 @@ func (*DefaultVerifier) VerifyBundleSignature(sc SignaturesConfig, bvc *Verifica } func verifyJWTSignature(token string, bvc *VerificationConfig) (*DecodedSignature, error) { - // decode JWT to check if the header specifies the key to use and/or if claims have the scope. - - parts, err := jws.SplitCompact(token) + tokbytes := []byte(token) + hdrb64, payloadb64, signatureb64, err := jwsbb.SplitCompact(tokbytes) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to split compact JWT: %w", err) } - var decodedHeader []byte - if decodedHeader, err = base64.RawURLEncoding.DecodeString(parts[0]); err != nil { - return nil, fmt.Errorf("failed to base64 decode JWT headers: %w", err) + // check for the id of the key to use for JWT signature verification + // first in the OPA config. If not found, then check the JWT kid. + keyID := bvc.KeyID + if keyID == "" { + // Use jwsbb.Header to access into the "kid" header field, which we will + // use to determine the key to use for verification. + hdr := jwsbb.HeaderParseCompact(hdrb64) + v, err := jwsbb.HeaderGetString(hdr, "kid") + switch { + case err == nil: + // err == nils means we found the key ID in the header + keyID = v + case errors.Is(err, jwsbb.ErrHeaderNotFound()): + // no "kid" in the header. no op. + default: + // some other error occurred while trying to extract the key ID + return nil, fmt.Errorf("failed to extract key ID from headers: %w", err) + } } - var hdr jws.StandardHeaders - if err := json.Unmarshal(decodedHeader, &hdr); err != nil { - return nil, fmt.Errorf("failed to parse JWT headers: %w", err) - } - - payload, err := base64.RawURLEncoding.DecodeString(parts[1]) - if err != nil { - return nil, err + // Because we want to fallback to ds.KeyID when we can't find the + // keyID, we need to parse the payload here already. + // + // (lestrrat) Whoa, you're going to trust the payload before you + // verify the signature? Even if it's for backwrds compatibility, + // Is this OK? + decoder := base64.RawURLEncoding + payload := make([]byte, decoder.DecodedLen(len(payloadb64))) + if _, err := decoder.Decode(payload, payloadb64); err != nil { + return nil, fmt.Errorf("failed to base64 decode JWT payload: %w", err) } var ds DecodedSignature @@ -109,17 +159,12 @@ func verifyJWTSignature(token string, bvc *VerificationConfig) (*DecodedSignatur return nil, err } - // check for the id of the key to use for JWT signature verification - // first in the OPA config. If not found, then check the JWT kid. - keyID := bvc.KeyID + // If header has no key id, check the deprecated key claim. if keyID == "" { - keyID = hdr.KeyID - } - if keyID == "" { - // If header has no key id, check the deprecated key claim. keyID = ds.KeyID } + // If we still don't have a keyID, we cannot proceed if keyID == "" { return nil, errors.New("verification key ID is empty") } @@ -130,16 +175,29 @@ func verifyJWTSignature(token string, bvc *VerificationConfig) (*DecodedSignatur return nil, err } - // verify JWT signature - alg := jwa.SignatureAlgorithm(keyConfig.Algorithm) - key, err := verify.GetSigningKey(keyConfig.Key, alg) + alg, ok := jwa.LookupSignatureAlgorithm(keyConfig.Algorithm) + if !ok { + return nil, fmt.Errorf("unknown signature algorithm: %s", keyConfig.Algorithm) + } + + // Parse the key into the appropriate type + parsedKey, err := parseVerificationKey(keyConfig.Key, alg) if err != nil { return nil, err } - _, err = jws.Verify([]byte(token), alg, key) - if err != nil { - return nil, err + signature := make([]byte, decoder.DecodedLen(len(signatureb64))) + if _, err = decoder.Decode(signature, signatureb64); err != nil { + return nil, fmt.Errorf("failed to base64 decode JWT signature: %w", err) + } + + signbuf := make([]byte, len(hdrb64)+1+len(payloadb64)) + copy(signbuf, hdrb64) + signbuf[len(hdrb64)] = '.' + copy(signbuf[len(hdrb64)+1:], payloadb64) + + if err := jwsbb.Verify(parsedKey, alg.String(), signbuf, signature); err != nil { + return nil, fmt.Errorf("failed to verify JWT signature: %w", err) } // verify the scope diff --git a/vendor/github.com/open-policy-agent/opa/v1/config/config.go b/vendor/github.com/open-policy-agent/opa/v1/config/config.go index 62bfc65537..1912d1f38c 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/config/config.go +++ b/vendor/github.com/open-policy-agent/opa/v1/config/config.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "os" "path/filepath" "reflect" @@ -21,6 +22,59 @@ import ( "github.com/open-policy-agent/opa/v1/version" ) +// ServerConfig represents the different server configuration options. +type ServerConfig struct { + Metrics json.RawMessage `json:"metrics,omitempty"` + + Encoding json.RawMessage `json:"encoding,omitempty"` + Decoding json.RawMessage `json:"decoding,omitempty"` +} + +// Clone creates a deep copy of ServerConfig. +func (s *ServerConfig) Clone() *ServerConfig { + if s == nil { + return nil + } + + clone := &ServerConfig{} + + if s.Encoding != nil { + clone.Encoding = make(json.RawMessage, len(s.Encoding)) + copy(clone.Encoding, s.Encoding) + } + if s.Decoding != nil { + clone.Decoding = make(json.RawMessage, len(s.Decoding)) + copy(clone.Decoding, s.Decoding) + } + if s.Metrics != nil { + clone.Metrics = make(json.RawMessage, len(s.Metrics)) + copy(clone.Metrics, s.Metrics) + } + + return clone +} + +// StorageConfig represents Config's storage options. +type StorageConfig struct { + Disk json.RawMessage `json:"disk,omitempty"` +} + +// Clone creates a deep copy of StorageConfig. +func (s *StorageConfig) Clone() *StorageConfig { + if s == nil { + return nil + } + + clone := &StorageConfig{} + + if s.Disk != nil { + clone.Disk = make(json.RawMessage, len(s.Disk)) + copy(clone.Disk, s.Disk) + } + + return clone +} + // Config represents the configuration file that OPA can be started with. type Config struct { Services json.RawMessage `json:"services,omitempty"` @@ -38,15 +92,9 @@ type Config struct { NDBuiltinCache bool `json:"nd_builtin_cache,omitempty"` PersistenceDirectory *string `json:"persistence_directory,omitempty"` DistributedTracing json.RawMessage `json:"distributed_tracing,omitempty"` - Server *struct { - Encoding json.RawMessage `json:"encoding,omitempty"` - Decoding json.RawMessage `json:"decoding,omitempty"` - Metrics json.RawMessage `json:"metrics,omitempty"` - } `json:"server,omitempty"` - Storage *struct { - Disk json.RawMessage `json:"disk,omitempty"` - } `json:"storage,omitempty"` - Extra map[string]json.RawMessage `json:"-"` + Server *ServerConfig `json:"server,omitempty"` + Storage *StorageConfig `json:"storage,omitempty"` + Extra map[string]json.RawMessage `json:"-"` } // ParseConfig returns a valid Config object with defaults injected. The id @@ -122,38 +170,6 @@ func (c Config) NDBuiltinCacheEnabled() bool { return c.NDBuiltinCache } -func (c *Config) validateAndInjectDefaults(id string) error { - - if c.DefaultDecision == nil { - s := defaultDecisionPath - c.DefaultDecision = &s - } - - _, err := ref.ParseDataPath(*c.DefaultDecision) - if err != nil { - return err - } - - if c.DefaultAuthorizationDecision == nil { - s := defaultAuthorizationDecisionPath - c.DefaultAuthorizationDecision = &s - } - - _, err = ref.ParseDataPath(*c.DefaultAuthorizationDecision) - if err != nil { - return err - } - - if c.Labels == nil { - c.Labels = map[string]string{} - } - - c.Labels["id"] = id - c.Labels["version"] = version.Version - - return nil -} - // GetPersistenceDirectory returns the configured persistence directory, or $PWD/.opa if none is configured func (c Config) GetPersistenceDirectory() (string, error) { if c.PersistenceDirectory == nil { @@ -197,6 +213,123 @@ func (c *Config) ActiveConfig() (any, error) { return result, nil } +// Clone creates a deep copy of the Config struct +func (c *Config) Clone() *Config { + if c == nil { + return nil + } + + clone := &Config{ + NDBuiltinCache: c.NDBuiltinCache, + Server: c.Server.Clone(), + Storage: c.Storage.Clone(), + Labels: maps.Clone(c.Labels), + } + + if c.Services != nil { + clone.Services = make(json.RawMessage, len(c.Services)) + copy(clone.Services, c.Services) + } + if c.Discovery != nil { + clone.Discovery = make(json.RawMessage, len(c.Discovery)) + copy(clone.Discovery, c.Discovery) + } + if c.Bundle != nil { + clone.Bundle = make(json.RawMessage, len(c.Bundle)) + copy(clone.Bundle, c.Bundle) + } + if c.Bundles != nil { + clone.Bundles = make(json.RawMessage, len(c.Bundles)) + copy(clone.Bundles, c.Bundles) + } + if c.DecisionLogs != nil { + clone.DecisionLogs = make(json.RawMessage, len(c.DecisionLogs)) + copy(clone.DecisionLogs, c.DecisionLogs) + } + if c.Status != nil { + clone.Status = make(json.RawMessage, len(c.Status)) + copy(clone.Status, c.Status) + } + if c.Keys != nil { + clone.Keys = make(json.RawMessage, len(c.Keys)) + copy(clone.Keys, c.Keys) + } + if c.Caching != nil { + clone.Caching = make(json.RawMessage, len(c.Caching)) + copy(clone.Caching, c.Caching) + } + if c.DistributedTracing != nil { + clone.DistributedTracing = make(json.RawMessage, len(c.DistributedTracing)) + copy(clone.DistributedTracing, c.DistributedTracing) + } + + if c.DefaultDecision != nil { + s := *c.DefaultDecision + clone.DefaultDecision = &s + } + if c.DefaultAuthorizationDecision != nil { + s := *c.DefaultAuthorizationDecision + clone.DefaultAuthorizationDecision = &s + } + if c.PersistenceDirectory != nil { + s := *c.PersistenceDirectory + clone.PersistenceDirectory = &s + } + + if c.Plugins != nil { + clone.Plugins = make(map[string]json.RawMessage, len(c.Plugins)) + for k, v := range c.Plugins { + if v != nil { + clone.Plugins[k] = make(json.RawMessage, len(v)) + copy(clone.Plugins[k], v) + } + } + } + + if c.Extra != nil { + clone.Extra = make(map[string]json.RawMessage, len(c.Extra)) + for k, v := range c.Extra { + if v != nil { + clone.Extra[k] = make(json.RawMessage, len(v)) + copy(clone.Extra[k], v) + } + } + } + + return clone +} + +func (c *Config) validateAndInjectDefaults(id string) error { + if c.DefaultDecision == nil { + s := defaultDecisionPath + c.DefaultDecision = &s + } + + _, err := ref.ParseDataPath(*c.DefaultDecision) + if err != nil { + return err + } + + if c.DefaultAuthorizationDecision == nil { + s := defaultAuthorizationDecisionPath + c.DefaultAuthorizationDecision = &s + } + + _, err = ref.ParseDataPath(*c.DefaultAuthorizationDecision) + if err != nil { + return err + } + + if c.Labels == nil { + c.Labels = map[string]string{} + } + + c.Labels["id"] = id + c.Labels["version"] = version.Version + + return nil +} + func removeServiceCredentials(x any) error { switch x := x.(type) { case nil: diff --git a/vendor/github.com/open-policy-agent/opa/v1/format/format.go b/vendor/github.com/open-policy-agent/opa/v1/format/format.go index a9cc32e3cb..4867594905 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/format/format.go +++ b/vendor/github.com/open-policy-agent/opa/v1/format/format.go @@ -277,22 +277,22 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { } err := w.writeModule(x) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Package: _, err := w.writePackage(x, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Import: _, err := w.writeImports([]*ast.Import{x}, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Rule: _, err := w.writeRule(x, false /* isElse */, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Head: _, err := w.writeHead(x, @@ -300,7 +300,7 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { false, // isExpandedConst nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case ast.Body: _, err := w.writeBody(x, nil) @@ -310,27 +310,27 @@ func AstWithOpts(x any, opts Opts) ([]byte, error) { case *ast.Expr: _, err := w.writeExpr(x, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.With: _, err := w.writeWith(x, nil, false) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Term: _, err := w.writeTerm(x, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case ast.Value: _, err := w.writeTerm(&ast.Term{Value: x, Location: &ast.Location{}}, nil) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } case *ast.Comment: err := w.writeComments([]*ast.Comment{x}) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } default: return nil, fmt.Errorf("not an ast element: %v", x) @@ -418,7 +418,7 @@ func (w *writer) writeModule(module *ast.Module) error { sort.Slice(comments, func(i, j int) bool { l, err := locLess(comments[i], comments[j]) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } return l }) @@ -426,7 +426,7 @@ func (w *writer) writeModule(module *ast.Module) error { sort.Slice(others, func(i, j int) bool { l, err := locLess(others[i], others[j]) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } return l }) @@ -524,12 +524,12 @@ func (w *writer) writeRules(rules []*ast.Rule, comments []*ast.Comment) ([]*ast. var err error comments, err = w.insertComments(comments, rule.Location) if err != nil && !errors.As(err, &unexpectedCommentError{}) { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } comments, err = w.writeRule(rule, false, comments) if err != nil && !errors.As(err, &unexpectedCommentError{}) { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } if i < len(rules)-1 && w.groupableOneLiner(rule) { @@ -874,7 +874,7 @@ func (w *writer) writeBody(body ast.Body, comments []*ast.Comment) ([]*ast.Comme comments, err = w.writeExpr(expr, comments) if err != nil && !errors.As(err, &unexpectedCommentError{}) { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } w.endLine() } @@ -1563,7 +1563,7 @@ func (w *writer) writeComprehensionBody(openChar, closeChar byte, body ast.Body, defer w.startLine() defer func() { if err := w.down(); err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } }() @@ -1627,7 +1627,7 @@ func (w *writer) writeImports(imports []*ast.Import, comments []*ast.Comment) ([ func (w *writer) writeImport(imp *ast.Import) error { path := imp.Path.Value.(ast.Ref) - buf := []string{"import"} + w.write("import ") if _, ok := future.WhichFutureKeyword(imp); ok { // We don't want to wrap future.keywords imports in parens, so we create a new writer that doesn't @@ -1638,15 +1638,17 @@ func (w *writer) writeImport(imp *ast.Import) error { if err != nil { return err } - buf = append(buf, w2.buf.String()) + w.write(w2.buf.String()) } else { - buf = append(buf, path.String()) + _, err := w.writeRef(path, nil) + if err != nil { + return err + } } if len(imp.Alias) > 0 { - buf = append(buf, "as "+imp.Alias.String()) + w.write(" as " + imp.Alias.String()) } - w.write(strings.Join(buf, " ")) return nil } @@ -1798,7 +1800,7 @@ func (w *writer) groupIterable(elements []any, last *ast.Location) ([][]any, err slices.SortFunc(elements, func(i, j any) int { l, err := locCmp(i, j) if err != nil { - w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, err.Error())) + w.errs = append(w.errs, ast.NewError(ast.FormatErr, &ast.Location{}, "%s", err.Error())) } return l }) diff --git a/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go b/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go index caf69b1242..cb756e5020 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go +++ b/vendor/github.com/open-policy-agent/opa/v1/hooks/hooks.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/open-policy-agent/opa/v1/config" + topdown_cache "github.com/open-policy-agent/opa/v1/topdown/cache" ) // Hook is a hook to be called in some select places in OPA's operation. @@ -49,6 +50,10 @@ func (hs Hooks) Each(fn func(Hook)) { } } +func (hs Hooks) Len() int { + return len(hs.m) +} + // ConfigHook allows inspecting or rewriting the configuration when the plugin // manager is processing it. // Note that this hook is not run when the plugin manager is reconfigured. This @@ -64,10 +69,25 @@ type ConfigDiscoveryHook interface { OnConfigDiscovery(context.Context, *config.Config) (*config.Config, error) } +// InterQueryCacheHook allows access to the server's inter-query cache instance. +// It's useful for out-of-tree handlers that also need to evaluate something. +// Using this hook, they can share the caches with the rest of OPA. +type InterQueryCacheHook interface { + OnInterQueryCache(context.Context, topdown_cache.InterQueryCache) error +} + +// InterQueryValueCacheHook allows access to the server's inter-query value cache +// instance. +type InterQueryValueCacheHook interface { + OnInterQueryValueCache(context.Context, topdown_cache.InterQueryValueCache) error +} + func (hs Hooks) Validate() error { for h := range hs.m { switch h.(type) { - case ConfigHook, + case InterQueryCacheHook, + InterQueryValueCacheHook, + ConfigHook, ConfigDiscoveryHook: // OK default: return fmt.Errorf("unknown hook type %T", h) diff --git a/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go b/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go index 079bf043cd..42a59d031f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go +++ b/vendor/github.com/open-policy-agent/opa/v1/loader/loader.go @@ -21,6 +21,7 @@ import ( "github.com/open-policy-agent/opa/v1/ast" astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/loader/extension" "github.com/open-policy-agent/opa/v1/loader/filter" "github.com/open-policy-agent/opa/v1/metrics" "github.com/open-policy-agent/opa/v1/storage" @@ -98,6 +99,7 @@ type FileLoader interface { WithFilter(Filter) FileLoader WithBundleVerificationConfig(*bundle.VerificationConfig) FileLoader WithSkipBundleVerification(bool) FileLoader + WithBundleLazyLoadingMode(bool) FileLoader WithProcessAnnotation(bool) FileLoader WithCapabilities(*ast.Capabilities) FileLoader // Deprecated: Use SetOptions in the json package instead, where a longer description @@ -116,15 +118,16 @@ func NewFileLoader() FileLoader { } type fileLoader struct { - metrics metrics.Metrics - filter Filter - bvc *bundle.VerificationConfig - skipVerify bool - files map[string]bundle.FileInfo - opts ast.ParserOptions - fsys fs.FS - reader io.Reader - followSymlinks bool + metrics metrics.Metrics + filter Filter + bvc *bundle.VerificationConfig + skipVerify bool + bundleLazyLoading bool + files map[string]bundle.FileInfo + opts ast.ParserOptions + fsys fs.FS + reader io.Reader + followSymlinks bool } // WithFS provides an fs.FS to use for loading files. You can pass nil to @@ -167,6 +170,12 @@ func (fl *fileLoader) WithSkipBundleVerification(skipVerify bool) FileLoader { return fl } +// WithBundleLazyLoadingMode enables or disables bundle lazy loading mode +func (fl *fileLoader) WithBundleLazyLoadingMode(bundleLazyLoading bool) FileLoader { + fl.bundleLazyLoading = bundleLazyLoading + return fl +} + // WithProcessAnnotation enables or disables processing of schema annotations on rules func (fl *fileLoader) WithProcessAnnotation(processAnnotation bool) FileLoader { fl.opts.ProcessAnnotation = processAnnotation @@ -223,7 +232,7 @@ func (fl fileLoader) Filtered(paths []string, filter Filter) (*Result, error) { return err } - result, err := loadKnownTypes(path, bs, fl.metrics, fl.opts) + result, err := loadKnownTypes(path, bs, fl.metrics, fl.opts, fl.bundleLazyLoading) if err != nil { if !isUnrecognizedFile(err) { return err @@ -271,10 +280,13 @@ func (fl fileLoader) AsBundle(path string) (*bundle.Bundle, error) { WithMetrics(fl.metrics). WithBundleVerificationConfig(fl.bvc). WithSkipBundleVerification(fl.skipVerify). + WithLazyLoadingMode(fl.bundleLazyLoading). WithProcessAnnotations(fl.opts.ProcessAnnotation). WithCapabilities(fl.opts.Capabilities). WithFollowSymlinks(fl.followSymlinks). - WithRegoVersion(fl.opts.RegoVersion) + WithRegoVersion(fl.opts.RegoVersion). + WithLazyLoadingMode(fl.bundleLazyLoading). + WithBundleName(path) // For bundle directories add the full path in front of module file names // to simplify debugging. @@ -719,8 +731,22 @@ func allRec(fsys fs.FS, path string, filter Filter, errors *Errors, loaded *Resu } } -func loadKnownTypes(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions) (any, error) { - switch filepath.Ext(path) { +func loadKnownTypes(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions, bundleLazyLoadingMode bool) (any, error) { + ext := filepath.Ext(path) + if handler := extension.FindExtension(ext); handler != nil { + m.Timer(metrics.RegoDataParse).Start() + + var value any + err := handler(bs, &value) + + m.Timer(metrics.RegoDataParse).Stop() + if err != nil { + return nil, fmt.Errorf("bundle %s: %w", path, err) + } + + return value, nil + } + switch ext { case ".json": return loadJSON(path, bs, m) case ".rego": @@ -729,7 +755,7 @@ func loadKnownTypes(path string, bs []byte, m metrics.Metrics, opts ast.ParserOp return loadYAML(path, bs, m) default: if strings.HasSuffix(path, ".tar.gz") { - r, err := loadBundleFile(path, bs, m, opts) + r, err := loadBundleFile(path, bs, m, opts, bundleLazyLoadingMode) if err != nil { err = fmt.Errorf("bundle %s: %w", path, err) } @@ -755,7 +781,7 @@ func loadFileForAnyType(path string, bs []byte, m metrics.Metrics, opts ast.Pars return nil, unrecognizedFile(path) } -func loadBundleFile(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions) (bundle.Bundle, error) { +func loadBundleFile(path string, bs []byte, m metrics.Metrics, opts ast.ParserOptions, bundleLazyLoadingMode bool) (bundle.Bundle, error) { tl := bundle.NewTarballLoaderWithBaseURL(bytes.NewBuffer(bs), path) br := bundle.NewCustomReader(tl). WithRegoVersion(opts.RegoVersion). @@ -763,6 +789,7 @@ func loadBundleFile(path string, bs []byte, m metrics.Metrics, opts ast.ParserOp WithProcessAnnotations(opts.ProcessAnnotation). WithMetrics(m). WithSkipBundleVerification(true). + WithLazyLoadingMode(bundleLazyLoadingMode). IncludeManifestInData(true) return br.Read() } diff --git a/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go b/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go index 9e36a20bf8..5ff27a2116 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go +++ b/vendor/github.com/open-policy-agent/opa/v1/logging/logging.go @@ -261,3 +261,14 @@ func DecisionIDFromContext(ctx context.Context) (string, bool) { s, ok := ctx.Value(decisionCtxKey).(string) return s, ok } + +const batchDecisionCtxKey = requestContextKey("batch_decision_id") + +func WithBatchDecisionID(parent context.Context, id string) context.Context { + return context.WithValue(parent, batchDecisionCtxKey, id) +} + +func BatchDecisionIDFromContext(ctx context.Context) (string, bool) { + s, ok := ctx.Value(batchDecisionCtxKey).(string) + return s, ok +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go b/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go index dc2afccdad..ca8df1ee48 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go +++ b/vendor/github.com/open-policy-agent/opa/v1/plugins/plugins.go @@ -177,7 +177,8 @@ type StatusListener func(status map[string]*Status) // Manager implements lifecycle management of plugins and gives plugins access // to engine-wide components like storage. type Manager struct { - Store storage.Store + Store storage.Store + // Config values should be accessed from the thread-safe GetConfig method. Config *config.Config Info *ast.Term ID string @@ -215,17 +216,25 @@ type Manager struct { bootstrapConfigLabels map[string]string hooks hooks.Hooks enableTelemetry bool - reporter *report.Reporter + reporter report.Reporter opaReportNotifyCh chan struct{} stop chan chan struct{} parserOptions ast.ParserOptions + extraRoutes map[string]ExtraRoute + extraMiddlewares []func(http.Handler) http.Handler + extraAuthorizerRoutes []func(string, []any) bool + bundleActivatorPlugin string } -type managerContextKey string -type managerWasmResolverKey string +type ( + managerContextKey string + managerWasmResolverKey string +) -const managerCompilerContextKey = managerContextKey("compiler") -const managerWasmResolverContextKey = managerWasmResolverKey("wasmResolvers") +const ( + managerCompilerContextKey = managerContextKey("compiler") + managerWasmResolverContextKey = managerWasmResolverKey("wasmResolvers") +) // SetCompilerOnContext puts the compiler into the storage context. Calling this // function before committing updated policies to storage allows the manager to @@ -272,7 +281,6 @@ func validateTriggerMode(mode TriggerMode) error { // ValidateAndInjectDefaultsForTriggerMode validates the trigger mode and injects default values func ValidateAndInjectDefaultsForTriggerMode(a, b *TriggerMode) (*TriggerMode, error) { - if a == nil && b != nil { err := validateTriggerMode(*b) if err != nil { @@ -425,9 +433,15 @@ func WithTelemetryGatherers(gs map[string]report.Gatherer) func(*Manager) { } } +// WithBundleActivatorPlugin sets the name of the activator plugin to load bundles into the store +func WithBundleActivatorPlugin(bundleActivatorPlugin string) func(*Manager) { + return func(m *Manager) { + m.bundleActivatorPlugin = bundleActivatorPlugin + } +} + // New creates a new Manager using config. func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*Manager, error) { - parsedConfig, err := config.ParseConfig(raw, id) if err != nil { return nil, err @@ -442,6 +456,7 @@ func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*M maxErrors: -1, serverInitialized: make(chan struct{}), bootstrapConfigLabels: parsedConfig.Labels, + extraRoutes: map[string]ExtraRoute{}, } for _, f := range opts { @@ -493,7 +508,7 @@ func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*M } if m.enableTelemetry { - reporter, err := report.New(id, report.Options{Logger: m.logger}) + reporter, err := report.New(report.Options{Logger: m.logger}) if err != nil { return nil, err } @@ -519,7 +534,6 @@ func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*M // Init returns an error if the manager could not initialize itself. Init() should // be called before Start(). Init() is idempotent. func (m *Manager) Init(ctx context.Context) error { - if m.initialized { return nil } @@ -536,7 +550,6 @@ func (m *Manager) Init(ctx context.Context) error { } err := storage.Txn(ctx, m.Store, params, func(txn storage.Transaction) error { - result, err := initload.InsertAndCompile(ctx, initload.InsertAndCompileOptions{ Store: m.Store, Txn: txn, @@ -545,8 +558,8 @@ func (m *Manager) Init(ctx context.Context) error { MaxErrors: m.maxErrors, EnablePrintStatements: m.enablePrintStatements, ParserOptions: m.parserOptions, + BundleActivatorPlugin: m.bundleActivatorPlugin, }) - if err != nil { return err } @@ -562,7 +575,6 @@ func (m *Manager) Init(ctx context.Context) error { _, err = m.Store.Register(ctx, txn, storage.TriggerConfig{OnCommit: m.onCommit}) return err }) - if err != nil { if m.stop != nil { done := make(chan struct{}) @@ -581,14 +593,24 @@ func (m *Manager) Init(ctx context.Context) error { func (m *Manager) Labels() map[string]string { m.mtx.Lock() defer m.mtx.Unlock() - return m.Config.Labels + + return maps.Clone(m.Config.Labels) } // InterQueryBuiltinCacheConfig returns the configuration for the inter-query caches. func (m *Manager) InterQueryBuiltinCacheConfig() *cache.Config { m.mtx.Lock() defer m.mtx.Unlock() - return m.interQueryBuiltinCacheConfig + + return m.interQueryBuiltinCacheConfig.Clone() +} + +// GetConfig returns a deep copy of the manager's configuration. +func (m *Manager) GetConfig() *config.Config { + m.mtx.Lock() + defer m.mtx.Unlock() + + return m.Config.Clone() } // Register adds a plugin to the manager. When the manager is started, all of @@ -653,6 +675,59 @@ func (m *Manager) setCompiler(compiler *ast.Compiler) { m.compiler = compiler } +type ExtraRoute struct { + PromName string // name is for prometheus metrics + HandlerFunc http.HandlerFunc +} + +func (m *Manager) ExtraRoutes() map[string]ExtraRoute { + return m.extraRoutes +} + +func (m *Manager) ExtraMiddlewares() []func(http.Handler) http.Handler { + return m.extraMiddlewares +} + +func (m *Manager) ExtraAuthorizerRoutes() []func(string, []any) bool { + return m.extraAuthorizerRoutes +} + +// ExtraRoute registers an extra route to be served by the HTTP +// server later. Using this instead of directly registering routes +// with GetRouter() lets the server apply its handler wrapping for +// Prometheus and OpenTelemetry. +// Caution: This cannot be used to dynamically register and un- +// register HTTP handlers. It's meant as a late-stage set up helper, +// to be called from a plugin's init methods. +func (m *Manager) ExtraRoute(path, name string, hf http.HandlerFunc) { + if _, ok := m.extraRoutes[path]; ok { + panic("extra route already registered: " + path) + } + m.extraRoutes[path] = ExtraRoute{ + PromName: name, + HandlerFunc: hf, + } +} + +// ExtraMiddleware registers extra middlewares (`func(http.Handler) http.Handler`) +// to be injected into the HTTP handler chain in the server later. +// Caution: This cannot be used to dynamically register and un- +// register middlewares. It's meant as a late-stage set up helper, +// to be called from a plugin's init methods. +func (m *Manager) ExtraMiddleware(mw ...func(http.Handler) http.Handler) { + m.extraMiddlewares = append(m.extraMiddlewares, mw...) +} + +// ExtraAuthorizerRoute registers an extra URL path validator function for use +// in the server authorizer. These functions designate specific methods and URL +// prefixes or paths where the authorizer should allow request body parsing. +// Caution: This cannot be used to dynamically register and un- +// register path validator functions. It's meant as a late-stage +// set up helper, to be called from a plugin's init methods. +func (m *Manager) ExtraAuthorizerRoute(validatorFunc func(string, []any) bool) { + m.extraAuthorizerRoutes = append(m.extraAuthorizerRoutes, validatorFunc) +} + // GetRouter returns the managers router if set func (m *Manager) GetRouter() *http.ServeMux { m.mtx.Lock() @@ -683,7 +758,6 @@ func (m *Manager) setWasmResolvers(rs []*wasm.Resolver) { // Start starts the manager. Init() should be called once before Start(). func (m *Manager) Start(ctx context.Context) error { - if m == nil { return nil } @@ -765,7 +839,9 @@ func (m *Manager) DefaultServiceOpts(config *config.Config) cfg.ServiceOptions { } // Reconfigure updates the configuration on the manager. -func (m *Manager) Reconfigure(config *config.Config) error { +func (m *Manager) Reconfigure(newCfg *config.Config) error { + config := newCfg.Clone() + opts := m.DefaultServiceOpts(config) keys, err := keys.ParseKeysConfig(config.Keys) @@ -796,6 +872,7 @@ func (m *Manager) Reconfigure(config *config.Config) error { // don't erase persistence directory if config.PersistenceDirectory == nil { + // update is ok since we have the lock config.PersistenceDirectory = m.Config.PersistenceDirectory } @@ -846,7 +923,6 @@ func (m *Manager) UnregisterPluginStatusListener(name string) { // listeners will be called with a copy of the new state of all // plugins. func (m *Manager) UpdatePluginStatus(pluginName string, status *Status) { - var toNotify map[string]StatusListener var statuses map[string]*Status @@ -880,7 +956,6 @@ func (m *Manager) copyPluginStatus() map[string]*Status { } func (m *Manager) onCommit(ctx context.Context, txn storage.Transaction, event storage.TriggerEvent) { - compiler := GetCompilerOnContext(event.Context) // If the context does not contain the compiler fallback to loading the @@ -908,7 +983,6 @@ func (m *Manager) onCommit(ctx context.Context, txn storage.Transaction, event s resolvers := getWasmResolversOnContext(event.Context) if resolvers != nil { m.setWasmResolvers(resolvers) - } else if event.DataChanged() { if requiresWasmResolverReload(event) { resolvers, err := bundleUtils.LoadWasmResolversFromStore(ctx, m.Store, txn, nil) @@ -991,7 +1065,19 @@ func (m *Manager) updateWasmResolversData(ctx context.Context, event storage.Tri func (m *Manager) PublicKeys() map[string]*keys.Config { m.mtx.Lock() defer m.mtx.Unlock() - return m.keys + + if m.keys == nil { + return make(map[string]*keys.Config) + } + + result := make(map[string]*keys.Config, len(m.keys)) + for k, v := range m.keys { + if v != nil { + copied := *v + result[k] = &copied + } + } + return result } // Client returns a client for communicating with a remote service. diff --git a/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go b/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go index 9a8d58cc66..3927a25435 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go +++ b/vendor/github.com/open-policy-agent/opa/v1/plugins/rest/auth.go @@ -29,9 +29,8 @@ import ( "strings" "time" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jws" - "github.com/open-policy-agent/opa/internal/jwx/jws/sign" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jws" "github.com/open-policy-agent/opa/internal/providers/aws" "github.com/open-policy-agent/opa/internal/uuid" "github.com/open-policy-agent/opa/v1/keys" @@ -391,11 +390,28 @@ func (ap *oauth2ClientCredentialsAuthPlugin) createAuthJWT(ctx context.Context, case ap.AzureKeyVault != nil: clientAssertion, err = ap.SignWithKeyVault(ctx, payload, header) default: - clientAssertion, err = jws.SignLiteral(payload, - jwa.SignatureAlgorithm(alg), - signingKey, - header, - rand.Reader) + // Parse the algorithm string to jwa.SignatureAlgorithm + algObj, ok := jwa.LookupSignatureAlgorithm(alg) + if !ok { + return nil, fmt.Errorf("unknown signature algorithm: %s", alg) + } + + // Parse headers + var headers map[string]interface{} + if err := json.Unmarshal(header, &headers); err != nil { + return nil, err + } + + // Create protected headers + protectedHeaders := jws.NewHeaders() + for k, v := range headers { + if err := protectedHeaders.Set(k, v); err != nil { + return nil, err + } + } + + clientAssertion, err = jws.Sign(payload, + jws.WithKey(algObj, signingKey, jws.WithProtectedHeaders(protectedHeaders))) } if err != nil { return nil, err @@ -485,8 +501,37 @@ func (ap *oauth2ClientCredentialsAuthPlugin) parseSigningKey(c Config) (err erro return errors.New("signing_key refers to non-existent key") } - alg := jwa.SignatureAlgorithm(ap.signingKey.Algorithm) - ap.signingKeyParsed, err = sign.GetSigningKey(ap.signingKey.PrivateKey, alg) + alg, ok := jwa.LookupSignatureAlgorithm(ap.signingKey.Algorithm) + if !ok { + return fmt.Errorf("unknown signature algorithm: %s", ap.signingKey.Algorithm) + } + + // Parse the private key directly + keyData := ap.signingKey.PrivateKey + + // For HMAC algorithms, return the key as bytes + if alg == jwa.HS256() || alg == jwa.HS384() || alg == jwa.HS512() { + ap.signingKeyParsed = []byte(keyData) + return nil + } + + // For RSA/ECDSA algorithms, parse the PEM-encoded key + block, _ := pem.Decode([]byte(keyData)) + if block == nil { + return errors.New("failed to decode PEM key") + } + + switch block.Type { + case "RSA PRIVATE KEY": + ap.signingKeyParsed, err = x509.ParsePKCS1PrivateKey(block.Bytes) + case "PRIVATE KEY": + ap.signingKeyParsed, err = x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + ap.signingKeyParsed, err = x509.ParseECPrivateKey(block.Bytes) + default: + return fmt.Errorf("unsupported key type: %s", block.Type) + } + if err != nil { return err } diff --git a/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go b/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go index 0f5365b9b0..8a47d90a93 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go +++ b/vendor/github.com/open-policy-agent/opa/v1/rego/rego.go @@ -126,6 +126,8 @@ type EvalContext struct { strictBuiltinErrors bool virtualCache topdown.VirtualCache baseCache topdown.BaseCache + tracing tracing.Options + externalCancel topdown.Cancel // Note(philip): If non-nil, the cancellation is handled outside of this package. } func (e *EvalContext) RawInput() *any { @@ -180,6 +182,18 @@ func (e *EvalContext) Transaction() storage.Transaction { return e.txn } +func (e *EvalContext) TracingOpts() tracing.Options { + return e.tracing +} + +func (e *EvalContext) ExternalCancel() topdown.Cancel { + return e.externalCancel +} + +func (e *EvalContext) QueryTracers() []topdown.QueryTracer { + return e.queryTracers +} + // EvalOption defines a function to set an option on an EvalConfig type EvalOption func(*EvalContext) @@ -388,6 +402,14 @@ func EvalNondeterministicBuiltins(yes bool) EvalOption { } } +// EvalExternalCancel sets an external topdown.Cancel for the interpreter to use +// for cancellation. This is useful for batch-evaluation of many rego queries. +func EvalExternalCancel(ec topdown.Cancel) EvalOption { + return func(e *EvalContext) { + e.externalCancel = ec + } +} + func (pq preparedQuery) Modules() map[string]*ast.Module { mods := make(map[string]*ast.Module) @@ -427,6 +449,7 @@ func (pq preparedQuery) newEvalContext(ctx context.Context, options []EvalOption printHook: pq.r.printHook, capabilities: pq.r.capabilities, strictBuiltinErrors: pq.r.strictBuiltinErrors, + tracing: pq.r.distributedTracingOpts, } for _, o := range options { @@ -625,6 +648,8 @@ type Rego struct { bundlePaths []string bundles map[string]*bundle.Bundle skipBundleVerification bool + bundleActivationPlugin string + enableBundleLazyLoadingMode bool interQueryBuiltinCache cache.InterQueryCache interQueryBuiltinValueCache cache.InterQueryValueCache ndBuiltinCache builtins.NDBCache @@ -643,6 +668,8 @@ type Rego struct { plugins []TargetPlugin targetPrepState TargetPluginEval regoVersion ast.RegoVersion + compilerHook func(*ast.Compiler) + evalMode *ast.CompilerEvalMode } func (r *Rego) RegoVersion() ast.RegoVersion { @@ -813,7 +840,6 @@ type memo struct { type memokey string func memoize(decl *Function, bctx BuiltinContext, terms []*ast.Term, ifEmpty func() (*ast.Term, error)) (*ast.Term, error) { - if !decl.Memoize { return ifEmpty() } @@ -1167,6 +1193,23 @@ func SkipBundleVerification(yes bool) func(r *Rego) { } } +// BundleActivatorPlugin sets the name of the activator plugin used to load bundles into the store. +func BundleActivatorPlugin(name string) func(r *Rego) { + return func(r *Rego) { + r.bundleActivationPlugin = name + } +} + +// BundleLazyLoadingMode sets the bundle loading mode. If true, bundles will be +// read in lazy mode. In this mode, data files in the bundle will not be +// deserialized and the check to validate that the bundle data does not contain +// paths outside the bundle's roots will not be performed while reading the bundle. +func BundleLazyLoadingMode(yes bool) func(r *Rego) { + return func(r *Rego) { + r.enableBundleLazyLoadingMode = yes + } +} + // InterQueryBuiltinCache sets the inter-query cache that built-in functions can utilize // during evaluation. func InterQueryBuiltinCache(c cache.InterQueryCache) func(r *Rego) { @@ -1278,9 +1321,23 @@ func SetRegoVersion(version ast.RegoVersion) func(r *Rego) { } } +// CompilerHook sets a hook function that will be called after the compiler is initialized. +// This is only called if the compiler has not been provided already. +func CompilerHook(hook func(*ast.Compiler)) func(r *Rego) { + return func(r *Rego) { + r.compilerHook = hook + } +} + +// EvalMode lets you override the evaluation mode. +func EvalMode(mode ast.CompilerEvalMode) func(r *Rego) { + return func(r *Rego) { + r.evalMode = &mode + } +} + // New returns a new Rego object. func New(options ...func(r *Rego)) *Rego { - r := &Rego{ parsedModules: map[string]*ast.Module{}, capture: map[*ast.Expr]ast.Var{}, @@ -1294,6 +1351,8 @@ func New(options ...func(r *Rego)) *Rego { option(r) } + callHook := r.compiler == nil // call hook only if we created the compiler here + if r.compiler == nil { r.compiler = ast.NewCompiler(). WithUnsafeBuiltins(r.unsafeBuiltins). @@ -1317,7 +1376,11 @@ func New(options ...func(r *Rego)) *Rego { } if r.store == nil { - r.store = inmem.NewWithOpts(inmem.OptReturnASTValuesOnRead(r.ownStoreReadAst)) + if bundle.HasExtension() { + r.store = bundle.BundleExtStore() + } else { + r.store = inmem.NewWithOpts(inmem.OptReturnASTValuesOnRead(r.ownStoreReadAst)) + } r.ownStore = true } else { r.ownStore = false @@ -1346,8 +1409,8 @@ func New(options ...func(r *Rego)) *Rego { } if r.pluginMgr != nil { - for _, name := range r.pluginMgr.Plugins() { - p := r.pluginMgr.Plugin(name) + for _, pluginName := range r.pluginMgr.Plugins() { + p := r.pluginMgr.Plugin(pluginName) if p0, ok := p.(TargetPlugin); ok { r.plugins = append(r.plugins, p0) } @@ -1358,6 +1421,14 @@ func New(options ...func(r *Rego)) *Rego { r.compiler = r.compiler.WithEvalMode(ast.EvalModeIR) } + if r.evalMode != nil { + r.compiler = r.compiler.WithEvalMode(*r.evalMode) + } + + if r.compilerHook != nil && callHook { + r.compilerHook(r.compiler) + } + return r } @@ -1501,7 +1572,6 @@ func CompilePartial(yes bool) CompileOption { // Compile returns a compiled policy query. func (r *Rego) Compile(ctx context.Context, opts ...CompileOption) (*CompileResult, error) { - var cfg CompileContext for _, opt := range opts { @@ -1876,6 +1946,11 @@ func (r *Rego) parseModules(ctx context.Context, txn storage.Transaction, m metr defer m.Timer(metrics.RegoModuleParse).Stop() var errs Errors + popts := ast.ParserOptions{ + RegoVersion: r.regoVersion, + Capabilities: r.capabilities, + } + // Parse any modules that are saved to the store, but only if // another compile step is going to occur (ie. we have parsed modules // that need to be compiled). @@ -1891,7 +1966,7 @@ func (r *Rego) parseModules(ctx context.Context, txn storage.Transaction, m metr return err } - parsed, err := ast.ParseModuleWithOpts(id, string(bs), ast.ParserOptions{RegoVersion: r.regoVersion}) + parsed, err := ast.ParseModuleWithOpts(id, string(bs), popts) if err != nil { errs = append(errs, err) } @@ -1901,7 +1976,7 @@ func (r *Rego) parseModules(ctx context.Context, txn storage.Transaction, m metr // Parse any passed in as arguments to the Rego object for _, module := range r.modules { - p, err := module.ParseWithOpts(ast.ParserOptions{RegoVersion: r.regoVersion}) + p, err := module.ParseWithOpts(popts) if err != nil { switch errorWithType := err.(type) { case ast.Errors: @@ -1933,6 +2008,7 @@ func (r *Rego) loadFiles(ctx context.Context, txn storage.Transaction, m metrics result, err := loader.NewFileLoader(). WithMetrics(m). WithProcessAnnotation(true). + WithBundleLazyLoadingMode(bundle.HasExtension()). WithRegoVersion(r.regoVersion). WithCapabilities(r.capabilities). Filtered(r.loadPaths.paths, r.loadPaths.filter) @@ -1964,6 +2040,7 @@ func (r *Rego) loadBundles(_ context.Context, _ storage.Transaction, m metrics.M bndl, err := loader.NewFileLoader(). WithMetrics(m). WithProcessAnnotation(true). + WithBundleLazyLoadingMode(bundle.HasExtension()). WithSkipBundleVerification(r.skipBundleVerification). WithRegoVersion(r.regoVersion). WithCapabilities(r.capabilities). @@ -2022,6 +2099,8 @@ func (r *Rego) parseQuery(queryImports []*ast.Import, m metrics.Metrics) (ast.Bo return nil, err } popts.SkipRules = true + popts.Capabilities = r.capabilities + return ast.ParseBodyWithOpts(r.query, popts) } @@ -2037,7 +2116,6 @@ func parserOptionsFromRegoVersionImport(imports []*ast.Import, popts ast.ParserO } func (r *Rego) compileModules(ctx context.Context, txn storage.Transaction, m metrics.Metrics) error { - // Only compile again if there are new modules. if len(r.bundles) > 0 || len(r.parsedModules) > 0 { @@ -2148,7 +2226,6 @@ func (r *Rego) compileQuery(query ast.Body, imports []*ast.Import, _ metrics.Met compiled, err := qc.Compile(query) return qc, compiled, err - } func (r *Rego) eval(ctx context.Context, ectx *EvalContext) (ResultSet, error) { @@ -2214,13 +2291,19 @@ func (r *Rego) eval(ctx context.Context, ectx *EvalContext) (ResultSet, error) { } // Cancel query if context is cancelled or deadline is reached. - c := topdown.NewCancel() - q = q.WithCancel(c) - exit := make(chan struct{}) - defer close(exit) - go waitForDone(ctx, exit, func() { - c.Cancel() - }) + if ectx.externalCancel == nil { + // Create a one-off goroutine to handle cancellation for this query. + c := topdown.NewCancel() + q = q.WithCancel(c) + exit := make(chan struct{}) + defer close(exit) + go waitForDone(ctx, exit, func() { + c.Cancel() + }) + } else { + // Query cancellation is being handled elsewhere. + q = q.WithCancel(ectx.externalCancel) + } var rs ResultSet err := q.Iter(ctx, func(qr topdown.QueryResult) error { @@ -2231,7 +2314,6 @@ func (r *Rego) eval(ctx context.Context, ectx *EvalContext) (ResultSet, error) { rs = append(rs, result) return nil }) - if err != nil { return nil, err } @@ -2304,7 +2386,6 @@ func (r *Rego) valueToQueryResult(res ast.Value, ectx *EvalContext) (ResultSet, } func (r *Rego) generateResult(qr topdown.QueryResult, ectx *EvalContext) (Result, error) { - rewritten := ectx.compiledQuery.compiler.RewrittenVars() result := newResult() @@ -2344,7 +2425,6 @@ func (r *Rego) generateResult(qr topdown.QueryResult, ectx *EvalContext) (Result } func (r *Rego) partialResult(ctx context.Context, pCfg *PrepareConfig) (PartialResult, error) { - err := r.prepare(ctx, partialResultQueryType, []extraStage{ { after: "ResolveRefs", @@ -2438,7 +2518,6 @@ func (r *Rego) partialResult(ctx context.Context, pCfg *PrepareConfig) (PartialR } func (r *Rego) partial(ctx context.Context, ectx *EvalContext) (*PartialQueries, error) { - var unknowns []*ast.Term switch { @@ -2502,13 +2581,19 @@ func (r *Rego) partial(ctx context.Context, ectx *EvalContext) (*PartialQueries, } // Cancel query if context is cancelled or deadline is reached. - c := topdown.NewCancel() - q = q.WithCancel(c) - exit := make(chan struct{}) - defer close(exit) - go waitForDone(ctx, exit, func() { - c.Cancel() - }) + if ectx.externalCancel == nil { + // Create a one-off goroutine to handle cancellation for this query. + c := topdown.NewCancel() + q = q.WithCancel(c) + exit := make(chan struct{}) + defer close(exit) + go waitForDone(ctx, exit, func() { + c.Cancel() + }) + } else { + // Query cancellation is being handled elsewhere. + q = q.WithCancel(ectx.externalCancel) + } queries, support, err := q.PartialRun(ctx) if err != nil { @@ -2570,7 +2655,6 @@ func (r *Rego) partial(ctx context.Context, ectx *EvalContext) (*PartialQueries, } func (r *Rego) rewriteQueryToCaptureValue(_ ast.QueryCompiler, query ast.Body) (ast.Body, error) { - checkCapture := iteration(query) || len(query) > 1 for _, expr := range query { @@ -2685,7 +2769,6 @@ type transactionCloser func(ctx context.Context, err error) error // the configured Rego object. The returned function should be used to close the txn // regardless of status. func (r *Rego) getTxn(ctx context.Context) (storage.Transaction, transactionCloser, error) { - noopCloser := func(_ context.Context, _ error) error { return nil // no-op default } @@ -2795,7 +2878,6 @@ type refResolver struct { } func iteration(x any) bool { - var stopped bool vis := ast.NewGenericVisitor(func(x any) bool { diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go b/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go index 1d03567066..a783caae09 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/interface.go @@ -49,6 +49,11 @@ type MakeDirer interface { MakeDir(context.Context, Transaction, Path) error } +// NonEmptyer allows a store implemention to override NonEmpty()) +type NonEmptyer interface { + NonEmpty(context.Context, Transaction) func([]string) (bool, error) +} + // TransactionParams describes a new transaction. type TransactionParams struct { diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go b/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go index ecc3829940..38d51be405 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/storage.go @@ -111,6 +111,9 @@ func Txn(ctx context.Context, store Store, params TransactionParams, f func(Tran // path is non-empty if a Read on the path returns a value or a Read // on any of the path prefixes returns a non-object value. func NonEmpty(ctx context.Context, store Store, txn Transaction) func([]string) (bool, error) { + if md, ok := store.(NonEmptyer); ok { + return md.NonEmpty(ctx, txn) + } return func(path []string) (bool, error) { if _, err := store.Read(ctx, txn, Path(path)); err == nil { return true, nil diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go index 60f38aaba2..d514bed787 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/cache/cache.go @@ -43,12 +43,40 @@ type Config struct { InterQueryBuiltinValueCache InterQueryBuiltinValueCacheConfig `json:"inter_query_builtin_value_cache"` } +// Clone creates a deep copy of Config. +func (c *Config) Clone() *Config { + if c == nil { + return nil + } + + return &Config{ + InterQueryBuiltinCache: *c.InterQueryBuiltinCache.Clone(), + InterQueryBuiltinValueCache: *c.InterQueryBuiltinValueCache.Clone(), + } +} + // NamedValueCacheConfig represents the configuration of a named cache that built-in functions can utilize. // A default configuration to be used if not explicitly configured can be registered using RegisterDefaultInterQueryBuiltinValueCacheConfig. type NamedValueCacheConfig struct { MaxNumEntries *int `json:"max_num_entries,omitempty"` } +// Clone creates a deep copy of NamedValueCacheConfig. +func (n *NamedValueCacheConfig) Clone() *NamedValueCacheConfig { + if n == nil { + return nil + } + + clone := &NamedValueCacheConfig{} + + if n.MaxNumEntries != nil { + maxEntries := *n.MaxNumEntries + clone.MaxNumEntries = &maxEntries + } + + return clone +} + // InterQueryBuiltinValueCacheConfig represents the configuration of the inter-query value cache that built-in functions can utilize. // MaxNumEntries - max number of cache entries type InterQueryBuiltinValueCacheConfig struct { @@ -56,6 +84,29 @@ type InterQueryBuiltinValueCacheConfig struct { NamedCacheConfigs map[string]*NamedValueCacheConfig `json:"named,omitempty"` } +// Clone creates a deep copy of InterQueryBuiltinValueCacheConfig. +func (i *InterQueryBuiltinValueCacheConfig) Clone() *InterQueryBuiltinValueCacheConfig { + if i == nil { + return nil + } + + clone := &InterQueryBuiltinValueCacheConfig{} + + if i.MaxNumEntries != nil { + maxEntries := *i.MaxNumEntries + clone.MaxNumEntries = &maxEntries + } + + if i.NamedCacheConfigs != nil { + clone.NamedCacheConfigs = make(map[string]*NamedValueCacheConfig, len(i.NamedCacheConfigs)) + for k, v := range i.NamedCacheConfigs { + clone.NamedCacheConfigs[k] = v.Clone() + } + } + + return clone +} + // InterQueryBuiltinCacheConfig represents the configuration of the inter-query cache that built-in functions can utilize. // MaxSizeBytes - max capacity of cache in bytes // ForcedEvictionThresholdPercentage - capacity usage in percentage after which forced FIFO eviction starts @@ -66,6 +117,32 @@ type InterQueryBuiltinCacheConfig struct { StaleEntryEvictionPeriodSeconds *int64 `json:"stale_entry_eviction_period_seconds,omitempty"` } +// Clone creates a deep copy of InterQueryBuiltinCacheConfig. +func (i *InterQueryBuiltinCacheConfig) Clone() *InterQueryBuiltinCacheConfig { + if i == nil { + return nil + } + + clone := &InterQueryBuiltinCacheConfig{} + + if i.MaxSizeBytes != nil { + maxSize := *i.MaxSizeBytes + clone.MaxSizeBytes = &maxSize + } + + if i.ForcedEvictionThresholdPercentage != nil { + threshold := *i.ForcedEvictionThresholdPercentage + clone.ForcedEvictionThresholdPercentage = &threshold + } + + if i.StaleEntryEvictionPeriodSeconds != nil { + period := *i.StaleEntryEvictionPeriodSeconds + clone.StaleEntryEvictionPeriodSeconds = &period + } + + return clone +} + // ParseCachingConfig returns the config for the inter-query cache. func ParseCachingConfig(raw []byte) (*Config, error) { if raw == nil { diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go index e582205f44..7767e7ff52 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go @@ -163,7 +163,8 @@ func (p *CopyPropagator) Apply(query ast.Body) ast.Body { // to the current result. // Invariant: Live vars are bound (above) and reserved vars are implicitly ground. - safe := ast.ReservedVars.Copy() + safe := ast.NewVarSetOfSize(len(p.livevars) + len(ast.ReservedVars) + 6) + safe.Update(ast.ReservedVars) safe.Update(p.livevars) safe.Update(ast.OutputVarsFromBody(p.compiler, result, safe)) unsafe := result.Vars(ast.SafetyCheckVisitorParams).Diff(safe) @@ -173,9 +174,8 @@ func (p *CopyPropagator) Apply(query ast.Body) ast.Body { providesSafety := false outputVars := ast.OutputVarsFromExpr(p.compiler, removedEq, safe) - diff := unsafe.Diff(outputVars) - if len(diff) < len(unsafe) { - unsafe = diff + if unsafe.DiffCount(outputVars) < len(unsafe) { + unsafe = unsafe.Diff(outputVars) providesSafety = true } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go index 2710d8a04a..144c01ee95 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/crypto.go @@ -25,7 +25,7 @@ import ( "strings" "time" - "github.com/open-policy-agent/opa/internal/jwx/jwk" + "github.com/lestrrat-go/jwx/v3/jwk" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/topdown/builtins" @@ -361,7 +361,7 @@ func builtinCryptoJWKFromPrivateKey(_ BuiltinContext, operands []*ast.Term, iter return iter(ast.InternedNullTerm) } - key, err := jwk.New(rawKeys[0]) + key, err := jwk.Import(rawKeys[0]) if err != nil { return err } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go index 023e9c09b3..f0f301e6a7 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go @@ -561,7 +561,6 @@ func (e *eval) fmtVarTerm() string { } func (e *eval) evalNot(iter evalIterator) error { - expr := e.query[e.index] if e.unknown(expr, e.bindings) { @@ -4106,8 +4105,7 @@ func canInlineNegation(safe ast.VarSet, queries []ast.Body) bool { SkipClosures: true, }) vis.Walk(expr) - unsafe := vis.Vars().Diff(safe).Diff(ast.ReservedVars) - if len(unsafe) > 0 { + if vis.Vars().Diff(safe).DiffCount(ast.ReservedVars) > 0 { return false } } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go index 831dc32b87..72d290073c 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/tokens.go @@ -7,11 +7,13 @@ package topdown import ( "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/hmac" "crypto/rsa" "crypto/sha256" "crypto/sha512" "crypto/x509" + "encoding/base64" "encoding/hex" "encoding/json" "encoding/pem" @@ -21,9 +23,9 @@ import ( "math/big" "strings" - "github.com/open-policy-agent/opa/internal/jwx/jwa" - "github.com/open-policy-agent/opa/internal/jwx/jwk" - "github.com/open-policy-agent/opa/internal/jwx/jws" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws/jwsbb" + "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/topdown/builtins" "github.com/open-policy-agent/opa/v1/topdown/cache" @@ -269,6 +271,31 @@ func verifyES(publicKey any, digest []byte, signature []byte) (err error) { return errors.New("ECDSA signature verification error") } +// Implements EdDSA JWT signature verification +func builtinJWTVerifyEdDSA(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerify(bctx, operands[0].Value, operands[1].Value, nil, verifyEd25519) + if err == nil { + return iter(ast.InternedTerm(result)) + } + return err +} + +func verifyEd25519(publicKey any, digest []byte, signature []byte) (err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("EdDSA signature verification error: %v", r) + } + }() + publicKeyEcdsa, ok := publicKey.(ed25519.PublicKey) + if !ok { + return errors.New("incorrect public key type") + } + if ed25519.Verify(publicKeyEcdsa, digest, signature) { + return nil + } + return errors.New("ECDSA signature verification error") +} + type verificationKey struct { alg string kid string @@ -309,15 +336,36 @@ func getKeysFromCertOrJWK(certificate string) ([]verificationKey, error) { return nil, fmt.Errorf("failed to parse a JWK key (set): %w", err) } - keys := make([]verificationKey, 0, len(jwks.Keys)) - for _, k := range jwks.Keys { - key, err := k.Materialize() - if err != nil { + keys := make([]verificationKey, 0, jwks.Len()) + for i := range jwks.Len() { + k, ok := jwks.Key(i) + if !ok { + continue + } + var key interface{} + if err := jwk.Export(k, &key); err != nil { return nil, err } + var alg string + if algInterface, ok := k.Algorithm(); ok { + alg = algInterface.String() + } + + // Skip keys with unknown/unsupported algorithms + if alg != "" { + if _, ok := tokenAlgorithms[alg]; !ok { + continue + } + } + + var kid string + if kidValue, ok := k.KeyID(); ok { + kid = kidValue + } + keys = append(keys, verificationKey{ - alg: k.GetAlgorithm().String(), - kid: k.GetKeyID(), + alg: alg, + kid: kid, key: key, }) } @@ -616,19 +664,13 @@ func (constraints *tokenConstraints) validate() error { // verify verifies a JWT using the constraints and the algorithm from the header func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature string) error { // Construct the payload - plaintext := []byte(header) - plaintext = append(plaintext, []byte(".")...) - plaintext = append(plaintext, payload...) - // Look up the algorithm - a, ok := tokenAlgorithms[alg] - if !ok { - return fmt.Errorf("unknown JWS algorithm: %s", alg) - } + plaintext := append(append([]byte(header), '.'), []byte(payload)...) + // If we're configured with asymmetric key(s) then only trust that if constraints.keys != nil { if kid != "" { if key := getKeyByKid(kid, constraints.keys); key != nil { - err := a.verify(key.key, a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature)) if err != nil { return errSignatureNotVerified } @@ -639,7 +681,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature verified := false for _, key := range constraints.keys { if key.alg == "" { - err := a.verify(key.key, a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature)) if err == nil { verified = true break @@ -648,7 +690,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature if alg != key.alg { continue } - err := a.verify(key.key, a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature)) if err == nil { verified = true break @@ -662,7 +704,11 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature return nil } if constraints.secret != "" { - return a.verify([]byte(constraints.secret), a.hash, plaintext, []byte(signature)) + err := jwsbb.Verify([]byte(constraints.secret), alg, plaintext, []byte(signature)) + if err != nil { + return errSignatureNotVerified + } + return nil } // (*tokenConstraints)validate() should prevent this happening return errors.New("unexpectedly found no keys to trust") @@ -689,101 +735,26 @@ func (constraints *tokenConstraints) validAudience(aud ast.Value) bool { // JWT algorithms -type ( - tokenVerifyFunction func(key any, hash crypto.Hash, payload []byte, signature []byte) error - tokenVerifyAsymmetricFunction func(key any, hash crypto.Hash, digest []byte, signature []byte) error -) - -// jwtAlgorithm describes a JWS 'alg' value -type tokenAlgorithm struct { - hash crypto.Hash - verify tokenVerifyFunction -} - // tokenAlgorithms is the known JWT algorithms -var tokenAlgorithms = map[string]tokenAlgorithm{ - "RS256": {crypto.SHA256, verifyAsymmetric(verifyRSAPKCS)}, - "RS384": {crypto.SHA384, verifyAsymmetric(verifyRSAPKCS)}, - "RS512": {crypto.SHA512, verifyAsymmetric(verifyRSAPKCS)}, - "PS256": {crypto.SHA256, verifyAsymmetric(verifyRSAPSS)}, - "PS384": {crypto.SHA384, verifyAsymmetric(verifyRSAPSS)}, - "PS512": {crypto.SHA512, verifyAsymmetric(verifyRSAPSS)}, - "ES256": {crypto.SHA256, verifyAsymmetric(verifyECDSA)}, - "ES384": {crypto.SHA384, verifyAsymmetric(verifyECDSA)}, - "ES512": {crypto.SHA512, verifyAsymmetric(verifyECDSA)}, - "HS256": {crypto.SHA256, verifyHMAC}, - "HS384": {crypto.SHA384, verifyHMAC}, - "HS512": {crypto.SHA512, verifyHMAC}, +var tokenAlgorithms = map[string]struct{}{ + "RS256": {}, + "RS384": {}, + "RS512": {}, + "PS256": {}, + "PS384": {}, + "PS512": {}, + "ES256": {}, + "ES384": {}, + "ES512": {}, + "HS256": {}, + "HS384": {}, + "HS512": {}, + "EdDSA": {}, } // errSignatureNotVerified is returned when a signature cannot be verified. var errSignatureNotVerified = errors.New("signature not verified") -func verifyHMAC(key any, hash crypto.Hash, payload []byte, signature []byte) error { - macKey, ok := key.([]byte) - if !ok { - return errors.New("incorrect symmetric key type") - } - mac := hmac.New(hash.New, macKey) - if _, err := mac.Write(payload); err != nil { - return err - } - if !hmac.Equal(signature, mac.Sum([]byte{})) { - return errSignatureNotVerified - } - return nil -} - -func verifyAsymmetric(verify tokenVerifyAsymmetricFunction) tokenVerifyFunction { - return func(key any, hash crypto.Hash, payload []byte, signature []byte) error { - h := hash.New() - h.Write(payload) - return verify(key, hash, h.Sum([]byte{}), signature) - } -} - -func verifyRSAPKCS(key any, hash crypto.Hash, digest []byte, signature []byte) error { - publicKeyRsa, ok := key.(*rsa.PublicKey) - if !ok { - return errors.New("incorrect public key type") - } - if err := rsa.VerifyPKCS1v15(publicKeyRsa, hash, digest, signature); err != nil { - return errSignatureNotVerified - } - return nil -} - -func verifyRSAPSS(key any, hash crypto.Hash, digest []byte, signature []byte) error { - publicKeyRsa, ok := key.(*rsa.PublicKey) - if !ok { - return errors.New("incorrect public key type") - } - if err := rsa.VerifyPSS(publicKeyRsa, hash, digest, signature, nil); err != nil { - return errSignatureNotVerified - } - return nil -} - -func verifyECDSA(key any, _ crypto.Hash, digest []byte, signature []byte) (err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("ECDSA signature verification error: %v", r) - } - }() - publicKeyEcdsa, ok := key.(*ecdsa.PublicKey) - if !ok { - return errors.New("incorrect public key type") - } - r, s := &big.Int{}, &big.Int{} - n := len(signature) / 2 - r.SetBytes(signature[:n]) - s.SetBytes(signature[n:]) - if ecdsa.Verify(publicKeyEcdsa, digest, r, s) { - return nil - } - return errSignatureNotVerified -} - // JWT header parsing and parameters. See tokens_test.go for unit tests. // tokenHeaderType represents a recognized JWT header field @@ -882,42 +853,48 @@ func (header *tokenHeader) valid() bool { return true } -func commonBuiltinJWTEncodeSign(bctx BuiltinContext, inputHeaders, jwsPayload, jwkSrc string, iter func(*ast.Term) error) error { - keys, err := jwk.ParseString(jwkSrc) +func commonBuiltinJWTEncodeSign(bctx BuiltinContext, inputHeaders, jwsPayload, jwkSrc []byte, iter func(*ast.Term) error) error { + keys, err := jwk.Parse(jwkSrc) if err != nil { return err } - key, err := keys.Keys[0].Materialize() - if err != nil { - return err - } - if jwk.GetKeyTypeFromKey(key) != keys.Keys[0].GetKeyType() { - return errors.New("JWK derived key type and keyType parameter do not match") - } - standardHeaders := &jws.StandardHeaders{} - jwsHeaders := []byte(inputHeaders) - err = json.Unmarshal(jwsHeaders, standardHeaders) - if err != nil { - return err - } - alg := standardHeaders.GetAlgorithm() - if alg == jwa.Unsupported { - return errors.New("unknown signature algorithm") + if keys.Len() == 0 { + return errors.New("no keys found in JWK set") } - if (standardHeaders.Type == "" || standardHeaders.Type == headerJwt) && !json.Valid([]byte(jwsPayload)) { + key, ok := keys.Key(0) + if !ok { + return errors.New("failed to get first key from JWK set") + } + + // Parse headers to get algorithm. + headers := jwsbb.HeaderParse(inputHeaders) + algStr, err := jwsbb.HeaderGetString(headers, "alg") + if err != nil { + return fmt.Errorf("missing or invalid 'alg' header: %w", err) + } + // Make sure the algorithm is supported. + _, ok = tokenAlgorithms[algStr] + if !ok { + return fmt.Errorf("unknown JWS algorithm: %s", algStr) + } + + typ, err := jwsbb.HeaderGetString(headers, "typ") + if (err != nil || typ == headerJwt) && !json.Valid(jwsPayload) { return errors.New("type is JWT but payload is not JSON") } - // process payload and sign - var jwsCompact []byte - jwsCompact, err = jws.SignLiteral([]byte(jwsPayload), alg, key, jwsHeaders, bctx.Seed) + payload := jwsbb.SignBuffer(nil, inputHeaders, jwsPayload, base64.RawURLEncoding, true) + + signature, err := jwsbb.Sign(key, algStr, payload, bctx.Seed) if err != nil { return err } - return iter(ast.StringTerm(string(jwsCompact))) + jwsCompact := string(payload) + "." + base64.RawURLEncoding.EncodeToString(signature) + + return iter(ast.StringTerm(jwsCompact)) } func builtinJWTEncodeSign(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { @@ -953,9 +930,9 @@ func builtinJWTEncodeSign(bctx BuiltinContext, operands []*ast.Term, iter func(* return commonBuiltinJWTEncodeSign( bctx, - string(inputHeadersBs), - string(payloadBs), - string(signatureBs), + inputHeadersBs, + payloadBs, + signatureBs, iter, ) } @@ -973,7 +950,7 @@ func builtinJWTEncodeSignRaw(bctx BuiltinContext, operands []*ast.Term, iter fun if err != nil { return err } - return commonBuiltinJWTEncodeSign(bctx, string(inputHeaders), string(jwsPayload), string(jwkSrc), iter) + return commonBuiltinJWTEncodeSign(bctx, []byte(inputHeaders), []byte(jwsPayload), []byte(jwkSrc), iter) } // Implements full JWT decoding, validation and verification. @@ -1248,6 +1225,10 @@ func extractJSONObject(s string) (ast.Object, error) { // getInputSha returns the SHA checksum of the input func getInputSHA(input []byte, h func() hash.Hash) []byte { + if h == nil { + return input + } + hasher := h() hasher.Write(input) return hasher.Sum(nil) @@ -1320,6 +1301,7 @@ func init() { RegisterBuiltinFunc(ast.JWTVerifyES256.Name, builtinJWTVerifyES256) RegisterBuiltinFunc(ast.JWTVerifyES384.Name, builtinJWTVerifyES384) RegisterBuiltinFunc(ast.JWTVerifyES512.Name, builtinJWTVerifyES512) + RegisterBuiltinFunc(ast.JWTVerifyEdDSA.Name, builtinJWTVerifyEdDSA) RegisterBuiltinFunc(ast.JWTVerifyHS256.Name, builtinJWTVerifyHS256) RegisterBuiltinFunc(ast.JWTVerifyHS384.Name, builtinJWTVerifyHS384) RegisterBuiltinFunc(ast.JWTVerifyHS512.Name, builtinJWTVerifyHS512) diff --git a/vendor/github.com/open-policy-agent/opa/v1/types/types.go b/vendor/github.com/open-policy-agent/opa/v1/types/types.go index f8d7db1ef0..366903f0cb 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/types/types.go +++ b/vendor/github.com/open-policy-agent/opa/v1/types/types.go @@ -17,6 +17,22 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) +var ( + // Nl represents an instance of the null type. + Nl Type = NewNull() + // B represents an instance of the boolean type. + B Type = NewBoolean() + // S represents an instance of the string type. + S Type = NewString() + // N represents an instance of the number type. + N Type = NewNumber() + // A represents the superset of all types. + A Type = NewAny() + + // Boxed set types. + SetOfAny, SetOfStr, SetOfNum Type = NewSet(A), NewSet(S), NewSet(N) +) + // Sprint returns the string representation of the type. func Sprint(x Type) string { if x == nil { @@ -50,8 +66,6 @@ func NewNull() Null { return Null{} } -var Nl Type = NewNull() - // NamedType represents a type alias with an arbitrary name and description. // This is useful for generating documentation for built-in functions. type NamedType struct { @@ -116,9 +130,6 @@ func (Null) String() string { // Boolean represents the boolean type. type Boolean struct{} -// B represents an instance of the boolean type. -var B Type = NewBoolean() - // NewBoolean returns a new Boolean type. func NewBoolean() Boolean { return Boolean{} @@ -139,9 +150,6 @@ func (t Boolean) String() string { // String represents the string type. type String struct{} -// S represents an instance of the string type. -var S Type = NewString() - // NewString returns a new String type. func NewString() String { return String{} @@ -161,9 +169,6 @@ func (String) String() string { // Number represents the number type. type Number struct{} -// N represents an instance of the number type. -var N Type = NewNumber() - // NewNumber returns a new Number type. func NewNumber() Number { return Number{} @@ -256,13 +261,6 @@ type Set struct { of Type } -// Boxed set types. -var ( - SetOfAny Type = NewSet(A) - SetOfStr Type = NewSet(S) - SetOfNum Type = NewSet(N) -) - // NewSet returns a new Set type. func NewSet(of Type) *Set { return &Set{ @@ -513,9 +511,6 @@ func mergeObjects(a, b *Object) *Object { // Any represents a dynamic type. type Any []Type -// A represents the superset of all types. -var A Type = NewAny() - // NewAny returns a new Any type. func NewAny(of ...Type) Any { sl := make(Any, len(of)) diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go b/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go index 1558f0cff8..d58af616da 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/backoff.go @@ -17,6 +17,8 @@ func DefaultBackoff(base, maxNS float64, retries int) time.Duration { // Backoff returns a delay with an exponential backoff based on the number of // retries. Same algorithm used in gRPC. +// Note that if maxNS is smaller than base, the backoff will still be capped at +// maxNS. func Backoff(base, maxNS, jitter, factor float64, retries int) time.Duration { if retries == 0 { return 0 diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/performance.go b/vendor/github.com/open-policy-agent/opa/v1/util/performance.go index 467fe766bb..e9b4468188 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/performance.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/performance.go @@ -62,3 +62,14 @@ func NumDigitsUint(n uint64) int { return int(math.Log10(float64(n))) + 1 } + +// KeysCount returns the number of keys in m that satisfy predicate p. +func KeysCount[K comparable, V any](m map[K]V, p func(K) bool) int { + count := 0 + for k := range m { + if p(k) { + count++ + } + } + return count +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/version/version.go b/vendor/github.com/open-policy-agent/opa/v1/version/version.go index ab229e76fe..ea6d25bbb4 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/version/version.go +++ b/vendor/github.com/open-policy-agent/opa/v1/version/version.go @@ -10,7 +10,7 @@ import ( "runtime/debug" ) -var Version = "1.6.0" +var Version = "1.8.0" // GoVersion is the version of Go this was built with var GoVersion = runtime.Version() diff --git a/vendor/github.com/segmentio/asm/LICENSE b/vendor/github.com/segmentio/asm/LICENSE new file mode 100644 index 0000000000..29e1ab6b05 --- /dev/null +++ b/vendor/github.com/segmentio/asm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Segment + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/segmentio/asm/base64/base64.go b/vendor/github.com/segmentio/asm/base64/base64.go new file mode 100644 index 0000000000..dd2128d4a9 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64.go @@ -0,0 +1,67 @@ +package base64 + +import ( + "encoding/base64" +) + +const ( + StdPadding rune = base64.StdPadding + NoPadding rune = base64.NoPadding + + encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" + encodeIMAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+," + + letterRange = int8('Z' - 'A' + 1) +) + +// StdEncoding is the standard base64 encoding, as defined in RFC 4648. +var StdEncoding = NewEncoding(encodeStd) + +// URLEncoding is the alternate base64 encoding defined in RFC 4648. +// It is typically used in URLs and file names. +var URLEncoding = NewEncoding(encodeURL) + +// RawStdEncoding is the standard unpadded base64 encoding defined in RFC 4648 section 3.2. +// This is the same as StdEncoding but omits padding characters. +var RawStdEncoding = StdEncoding.WithPadding(NoPadding) + +// RawURLEncoding is the unpadded alternate base64 encoding defined in RFC 4648. +// This is the same as URLEncoding but omits padding characters. +var RawURLEncoding = URLEncoding.WithPadding(NoPadding) + +// NewEncoding returns a new padded Encoding defined by the given alphabet, +// which must be a 64-byte string that does not contain the padding character +// or CR / LF ('\r', '\n'). Unlike the standard library, the encoding alphabet +// cannot be abitrary, and it must follow one of the know standard encoding +// variants. +// +// Required alphabet values: +// * [0,26): characters 'A'..'Z' +// * [26,52): characters 'a'..'z' +// * [52,62): characters '0'..'9' +// Flexible alphabet value options: +// * RFC 4648, RFC 1421, RFC 2045, RFC 2152, RFC 4880: '+' and '/' +// * RFC 4648 URI: '-' and '_' +// * RFC 3501: '+' and ',' +// +// The resulting Encoding uses the default padding character ('='), which may +// be changed or disabled via WithPadding. The padding characters is urestricted, +// but it must be a character outside of the encoder alphabet. +func NewEncoding(encoder string) *Encoding { + if len(encoder) != 64 { + panic("encoding alphabet is not 64-bytes long") + } + + if _, ok := allowedEncoding[encoder]; !ok { + panic("non-standard encoding alphabets are not supported") + } + + return newEncoding(encoder) +} + +var allowedEncoding = map[string]struct{}{ + encodeStd: {}, + encodeURL: {}, + encodeIMAP: {}, +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_amd64.go b/vendor/github.com/segmentio/asm/base64/base64_amd64.go new file mode 100644 index 0000000000..4136098eaa --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_amd64.go @@ -0,0 +1,78 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package base64 + +import ( + "encoding/base64" + + "github.com/segmentio/asm/cpu" + "github.com/segmentio/asm/cpu/x86" +) + +const ( + encLutSize = 32 + decLutSize = 48 + minEncodeLen = 28 + minDecodeLen = 45 +) + +func newEncoding(encoder string) *Encoding { + e := &Encoding{base: base64.NewEncoding(encoder)} + if cpu.X86.Has(x86.AVX2) { + e.enableEncodeAVX2(encoder) + e.enableDecodeAVX2(encoder) + } + return e +} + +func (e *Encoding) enableEncodeAVX2(encoder string) { + // Translate values 0..63 to the Base64 alphabet. There are five sets: + // + // From To Add Index Example + // [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ + // [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz + // [52..61] [48..57] -4 [2..11] 0123456789 + // [62] [43] -19 12 + + // [63] [47] -16 13 / + tab := [encLutSize]int8{int8(encoder[0]), int8(encoder[letterRange]) - letterRange} + for i, ch := range encoder[2*letterRange:] { + tab[2+i] = int8(ch) - 2*letterRange - int8(i) + } + + e.enc = encodeAVX2 + e.enclut = tab +} + +func (e *Encoding) enableDecodeAVX2(encoder string) { + c62, c63 := int8(encoder[62]), int8(encoder[63]) + url := c63 == '_' + if url { + c63 = '/' + } + + // Translate values from the Base64 alphabet using five sets. Values outside + // of these ranges are considered invalid: + // + // From To Add Index Example + // [47] [63] +16 1 / + // [43] [62] +19 2 + + // [48..57] [52..61] +4 3 0123456789 + // [65..90] [0..25] -65 4,5 ABCDEFGHIJKLMNOPQRSTUVWXYZ + // [97..122] [26..51] -71 6,7 abcdefghijklmnopqrstuvwxyz + tab := [decLutSize]int8{ + 0, 63 - c63, 62 - c62, 4, -65, -65, -71, -71, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x13, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + } + tab[(c62&15)+16] = 0x1A + tab[(c63&15)+16] = 0x1A + + if url { + e.dec = decodeAVX2URI + } else { + e.dec = decodeAVX2 + } + e.declut = tab +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_arm64.go b/vendor/github.com/segmentio/asm/base64/base64_arm64.go new file mode 100644 index 0000000000..276f300287 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_arm64.go @@ -0,0 +1,42 @@ +//go:build arm64 && !purego +// +build arm64,!purego + +package base64 + +import ( + "encoding/base64" +) + +const ( + encLutSize = 16 + decLutSize = 2 + minEncodeLen = 16 * 3 + minDecodeLen = 8 * 4 +) + +func newEncoding(encoder string) *Encoding { + e := &Encoding{base: base64.NewEncoding(encoder)} + e.enableEncodeARM64(encoder) + e.enableDecodeARM64(encoder) + return e +} + +func (e *Encoding) enableEncodeARM64(encoder string) { + c62, c63 := int8(encoder[62]), int8(encoder[63]) + tab := [encLutSize]int8{ + 'a' - 26, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, + '0' - 52, '0' - 52, '0' - 52, c62 - 62, c63 - 63, 'A', 0, 0, + } + + e.enc = encodeARM64 + e.enclut = tab +} + +func (e *Encoding) enableDecodeARM64(encoder string) { + if encoder == encodeStd { + e.dec = decodeStdARM64 + } else { + e.dec = decodeARM64 + } + e.declut = [decLutSize]int8{int8(encoder[62]), int8(encoder[63])} +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_asm.go b/vendor/github.com/segmentio/asm/base64/base64_asm.go new file mode 100644 index 0000000000..f9afadd7f2 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_asm.go @@ -0,0 +1,94 @@ +//go:build (amd64 || arm64) && !purego +// +build amd64 arm64 +// +build !purego + +package base64 + +import ( + "encoding/base64" + + "github.com/segmentio/asm/internal/unsafebytes" +) + +// An Encoding is a radix 64 encoding/decoding scheme, defined by a +// 64-character alphabet. +type Encoding struct { + enc func(dst []byte, src []byte, lut *int8) (int, int) + enclut [encLutSize]int8 + + dec func(dst []byte, src []byte, lut *int8) (int, int) + declut [decLutSize]int8 + + base *base64.Encoding +} + +// WithPadding creates a duplicate Encoding updated with a specified padding +// character, or NoPadding to disable padding. The padding character must not +// be contained in the encoding alphabet, must not be '\r' or '\n', and must +// be no greater than '\xFF'. +func (enc Encoding) WithPadding(padding rune) *Encoding { + enc.base = enc.base.WithPadding(padding) + return &enc +} + +// Strict creates a duplicate encoding updated with strict decoding enabled. +// This requires that trailing padding bits are zero. +func (enc Encoding) Strict() *Encoding { + enc.base = enc.base.Strict() + return &enc +} + +// Encode encodes src using the defined encoding alphabet. +// This will write EncodedLen(len(src)) bytes to dst. +func (enc *Encoding) Encode(dst, src []byte) { + if len(src) >= minEncodeLen && enc.enc != nil { + d, s := enc.enc(dst, src, &enc.enclut[0]) + dst = dst[d:] + src = src[s:] + } + enc.base.Encode(dst, src) +} + +// Encode encodes src using the encoding enc, writing +// EncodedLen(len(src)) bytes to dst. +func (enc *Encoding) EncodeToString(src []byte) string { + buf := make([]byte, enc.base.EncodedLen(len(src))) + enc.Encode(buf, src) + return string(buf) +} + +// EncodedLen calculates the base64-encoded byte length for a message +// of length n. +func (enc *Encoding) EncodedLen(n int) int { + return enc.base.EncodedLen(n) +} + +// Decode decodes src using the defined encoding alphabet. +// This will write DecodedLen(len(src)) bytes to dst and return the number of +// bytes written. +func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { + var d, s int + if len(src) >= minDecodeLen && enc.dec != nil { + d, s = enc.dec(dst, src, &enc.declut[0]) + dst = dst[d:] + src = src[s:] + } + n, err = enc.base.Decode(dst, src) + n += d + return +} + +// DecodeString decodes the base64 encoded string s, returns the decoded +// value as bytes. +func (enc *Encoding) DecodeString(s string) ([]byte, error) { + src := unsafebytes.BytesOf(s) + dst := make([]byte, enc.base.DecodedLen(len(s))) + n, err := enc.Decode(dst, src) + return dst[:n], err +} + +// DecodedLen calculates the decoded byte length for a base64-encoded message +// of length n. +func (enc *Encoding) DecodedLen(n int) int { + return enc.base.DecodedLen(n) +} diff --git a/vendor/github.com/segmentio/asm/base64/base64_default.go b/vendor/github.com/segmentio/asm/base64/base64_default.go new file mode 100644 index 0000000000..1720da5ca7 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/base64_default.go @@ -0,0 +1,14 @@ +//go:build purego || !(amd64 || arm64) +// +build purego !amd64,!arm64 + +package base64 + +import "encoding/base64" + +// An Encoding is a radix 64 encoding/decoding scheme, defined by a +// 64-character alphabet. +type Encoding = base64.Encoding + +func newEncoding(encoder string) *Encoding { + return base64.NewEncoding(encoder) +} diff --git a/vendor/github.com/segmentio/asm/base64/decode_amd64.go b/vendor/github.com/segmentio/asm/base64/decode_amd64.go new file mode 100644 index 0000000000..e85bf6a925 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_amd64.go @@ -0,0 +1,9 @@ +// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT. + +//go:build !purego + +package base64 + +func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int) + +func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/decode_amd64.s b/vendor/github.com/segmentio/asm/base64/decode_amd64.s new file mode 100644 index 0000000000..ade5442c3b --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_amd64.s @@ -0,0 +1,143 @@ +// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT. + +//go:build !purego + +#include "textflag.h" + +DATA b64_dec_lut_hi<>+0(SB)/8, $0x0804080402011010 +DATA b64_dec_lut_hi<>+8(SB)/8, $0x1010101010101010 +DATA b64_dec_lut_hi<>+16(SB)/8, $0x0804080402011010 +DATA b64_dec_lut_hi<>+24(SB)/8, $0x1010101010101010 +GLOBL b64_dec_lut_hi<>(SB), RODATA|NOPTR, $32 + +DATA b64_dec_madd1<>+0(SB)/8, $0x0140014001400140 +DATA b64_dec_madd1<>+8(SB)/8, $0x0140014001400140 +DATA b64_dec_madd1<>+16(SB)/8, $0x0140014001400140 +DATA b64_dec_madd1<>+24(SB)/8, $0x0140014001400140 +GLOBL b64_dec_madd1<>(SB), RODATA|NOPTR, $32 + +DATA b64_dec_madd2<>+0(SB)/8, $0x0001100000011000 +DATA b64_dec_madd2<>+8(SB)/8, $0x0001100000011000 +DATA b64_dec_madd2<>+16(SB)/8, $0x0001100000011000 +DATA b64_dec_madd2<>+24(SB)/8, $0x0001100000011000 +GLOBL b64_dec_madd2<>(SB), RODATA|NOPTR, $32 + +DATA b64_dec_shuf_lo<>+0(SB)/8, $0x0000000000000000 +DATA b64_dec_shuf_lo<>+8(SB)/8, $0x0600010200000000 +GLOBL b64_dec_shuf_lo<>(SB), RODATA|NOPTR, $16 + +DATA b64_dec_shuf<>+0(SB)/8, $0x090a040506000102 +DATA b64_dec_shuf<>+8(SB)/8, $0x000000000c0d0e08 +DATA b64_dec_shuf<>+16(SB)/8, $0x0c0d0e08090a0405 +DATA b64_dec_shuf<>+24(SB)/8, $0x0000000000000000 +GLOBL b64_dec_shuf<>(SB), RODATA|NOPTR, $32 + +// func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int) +// Requires: AVX, AVX2, SSE4.1 +TEXT ·decodeAVX2(SB), NOSPLIT, $0-72 + MOVQ dst_base+0(FP), AX + MOVQ src_base+24(FP), DX + MOVQ lut+48(FP), SI + MOVQ src_len+32(FP), DI + MOVB $0x2f, CL + PINSRB $0x00, CX, X8 + VPBROADCASTB X8, Y8 + XORQ CX, CX + XORQ BX, BX + VPXOR Y7, Y7, Y7 + VPERMQ $0x44, (SI), Y6 + VPERMQ $0x44, 16(SI), Y4 + VMOVDQA b64_dec_lut_hi<>+0(SB), Y5 + +loop: + VMOVDQU (DX)(BX*1), Y0 + VPSRLD $0x04, Y0, Y2 + VPAND Y8, Y0, Y3 + VPSHUFB Y3, Y4, Y3 + VPAND Y8, Y2, Y2 + VPSHUFB Y2, Y5, Y9 + VPTEST Y9, Y3 + JNE done + VPCMPEQB Y8, Y0, Y3 + VPADDB Y3, Y2, Y2 + VPSHUFB Y2, Y6, Y2 + VPADDB Y0, Y2, Y0 + VPMADDUBSW b64_dec_madd1<>+0(SB), Y0, Y0 + VPMADDWD b64_dec_madd2<>+0(SB), Y0, Y0 + VEXTRACTI128 $0x01, Y0, X1 + VPSHUFB b64_dec_shuf_lo<>+0(SB), X1, X1 + VPSHUFB b64_dec_shuf<>+0(SB), Y0, Y0 + VPBLENDD $0x08, Y1, Y0, Y1 + VPBLENDD $0xc0, Y7, Y1, Y1 + VMOVDQU Y1, (AX)(CX*1) + ADDQ $0x18, CX + ADDQ $0x20, BX + SUBQ $0x20, DI + CMPQ DI, $0x2d + JB done + JMP loop + +done: + MOVQ CX, ret+56(FP) + MOVQ BX, ret1+64(FP) + VZEROUPPER + RET + +// func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int) +// Requires: AVX, AVX2, SSE4.1 +TEXT ·decodeAVX2URI(SB), NOSPLIT, $0-72 + MOVB $0x2f, AL + PINSRB $0x00, AX, X0 + VPBROADCASTB X0, Y0 + MOVB $0x5f, AL + PINSRB $0x00, AX, X1 + VPBROADCASTB X1, Y1 + MOVQ dst_base+0(FP), AX + MOVQ src_base+24(FP), DX + MOVQ lut+48(FP), SI + MOVQ src_len+32(FP), DI + MOVB $0x2f, CL + PINSRB $0x00, CX, X10 + VPBROADCASTB X10, Y10 + XORQ CX, CX + XORQ BX, BX + VPXOR Y9, Y9, Y9 + VPERMQ $0x44, (SI), Y8 + VPERMQ $0x44, 16(SI), Y6 + VMOVDQA b64_dec_lut_hi<>+0(SB), Y7 + +loop: + VMOVDQU (DX)(BX*1), Y2 + VPCMPEQB Y2, Y1, Y4 + VPBLENDVB Y4, Y0, Y2, Y2 + VPSRLD $0x04, Y2, Y4 + VPAND Y10, Y2, Y5 + VPSHUFB Y5, Y6, Y5 + VPAND Y10, Y4, Y4 + VPSHUFB Y4, Y7, Y11 + VPTEST Y11, Y5 + JNE done + VPCMPEQB Y10, Y2, Y5 + VPADDB Y5, Y4, Y4 + VPSHUFB Y4, Y8, Y4 + VPADDB Y2, Y4, Y2 + VPMADDUBSW b64_dec_madd1<>+0(SB), Y2, Y2 + VPMADDWD b64_dec_madd2<>+0(SB), Y2, Y2 + VEXTRACTI128 $0x01, Y2, X3 + VPSHUFB b64_dec_shuf_lo<>+0(SB), X3, X3 + VPSHUFB b64_dec_shuf<>+0(SB), Y2, Y2 + VPBLENDD $0x08, Y3, Y2, Y3 + VPBLENDD $0xc0, Y9, Y3, Y3 + VMOVDQU Y3, (AX)(CX*1) + ADDQ $0x18, CX + ADDQ $0x20, BX + SUBQ $0x20, DI + CMPQ DI, $0x2d + JB done + JMP loop + +done: + MOVQ CX, ret+56(FP) + MOVQ BX, ret1+64(FP) + VZEROUPPER + RET diff --git a/vendor/github.com/segmentio/asm/base64/decode_arm64.go b/vendor/github.com/segmentio/asm/base64/decode_arm64.go new file mode 100644 index 0000000000..d44baa1dc5 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_arm64.go @@ -0,0 +1,7 @@ +//go:build !purego +// +build !purego + +package base64 + +func decodeARM64(dst []byte, src []byte, lut *int8) (int, int) +func decodeStdARM64(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/decode_arm64.s b/vendor/github.com/segmentio/asm/base64/decode_arm64.s new file mode 100644 index 0000000000..4374d5ce17 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/decode_arm64.s @@ -0,0 +1,203 @@ +#include "textflag.h" + +#define LOAD_ARGS() \ + MOVD dst_base+0(FP), R0; \ + MOVD R0, R3; \ + MOVD src_base+24(FP), R1; \ + MOVD R1, R4; \ + MOVD src_len+32(FP), R2; \ + BIC $31, R2, R2; \ + ADD R1, R2, R2 + +#define LOAD_ARG_LUT() \ + MOVD lut+48(FP), R5; \ + VLD2R (R5), [V0.B16, V1.B16] + +#define LOAD_CONST_LUT() \ + MOVD $·mask_lut(SB), R6; \ + MOVD $·bpos_lut(SB), R7; \ + MOVD $·shft_lut(SB), R8; \ + VLD1 (R6), [V2.B16]; \ + VLD1 (R7), [V3.B16]; \ + VLD1 (R8), [V4.B16]; \ + VMOVI $43, V5.B8; \ + VMOVI $47, V6.B8; \ + VMOVI $15, V7.B8; \ + VMOVI $16, V8.B8; \ + +#define LOAD_INPUT() \ + VLD4 (R4), [V10.B8, V11.B8, V12.B8, V13.B8] + +#define COMPARE_INPUT(v) \ + VCMEQ V10.B8, v.B8, V14.B8; \ + VCMEQ V11.B8, v.B8, V15.B8; \ + VCMEQ V12.B8, v.B8, V16.B8; \ + VCMEQ V13.B8, v.B8, V17.B8 + +#define UPDATE_INPUT(v) \ + VBIT V14.B8, v.B8, V10.B8; \ + VBIT V15.B8, v.B8, V11.B8; \ + VBIT V16.B8, v.B8, V12.B8; \ + VBIT V17.B8, v.B8, V13.B8 + +#define DECODE_INPUT(goto_err) \ + /* Create hi/lo nibles */ \ + VUSHR $4, V10.B8, V18.B8; \ + VUSHR $4, V11.B8, V19.B8; \ + VUSHR $4, V12.B8, V20.B8; \ + VUSHR $4, V13.B8, V21.B8; \ + VAND V7.B8, V10.B8, V22.B8; \ + VAND V7.B8, V11.B8, V23.B8; \ + VAND V7.B8, V12.B8, V24.B8; \ + VAND V7.B8, V13.B8, V25.B8; \ + /* Detect invalid input characters */ \ + VTBL V22.B8, [V2.B8], V22.B8; \ + VTBL V23.B8, [V2.B8], V23.B8; \ + VTBL V24.B8, [V2.B8], V24.B8; \ + VTBL V25.B8, [V2.B8], V25.B8; \ + VTBL V18.B8, [V3.B8], V26.B8; \ + VTBL V19.B8, [V3.B8], V27.B8; \ + VTBL V20.B8, [V3.B8], V28.B8; \ + VTBL V21.B8, [V3.B8], V29.B8; \ + VAND V22.B8, V26.B8, V26.B8; \ + VAND V23.B8, V27.B8, V27.B8; \ + VAND V24.B8, V28.B8, V28.B8; \ + VAND V25.B8, V29.B8, V29.B8; \ + WORD $0x0e209b5a /* VCMEQ $0, V26.B8, V26.B8 */; \ + WORD $0x0e209b7b /* VCMEQ $0, V27.B8, V27.B8 */; \ + WORD $0x0e209b9c /* VCMEQ $0, V28.B8, V28.B8 */; \ + WORD $0x0e209bbd /* VCMEQ $0, V29.B8, V29.B8 */; \ + VORR V26.B8, V27.B8, V26.B8; \ + VORR V28.B8, V29.B8, V28.B8; \ + VORR V26.B8, V28.B8, V26.B8; \ + VMOV V26.D[0], R5; \ + VMOV V26.D[1], R6; \ + ORR R6, R5; \ + CBNZ R5, goto_err; \ + /* Shift hi nibles */ \ + VTBL V18.B8, [V4.B8], V18.B8; \ + VTBL V19.B8, [V4.B8], V19.B8; \ + VTBL V20.B8, [V4.B8], V20.B8; \ + VTBL V21.B8, [V4.B8], V21.B8; \ + VBIT V14.B8, V8.B8, V18.B8; \ + VBIT V15.B8, V8.B8, V19.B8; \ + VBIT V16.B8, V8.B8, V20.B8; \ + VBIT V17.B8, V8.B8, V21.B8; \ + /* Combine results */ \ + VADD V18.B8, V10.B8, V10.B8; \ + VADD V19.B8, V11.B8, V11.B8; \ + VADD V20.B8, V12.B8, V12.B8; \ + VADD V21.B8, V13.B8, V13.B8; \ + VUSHR $4, V11.B8, V14.B8; \ + VUSHR $2, V12.B8, V15.B8; \ + VSHL $2, V10.B8, V10.B8; \ + VSHL $4, V11.B8, V11.B8; \ + VSHL $6, V12.B8, V12.B8; \ + VORR V10.B8, V14.B8, V16.B8; \ + VORR V11.B8, V15.B8, V17.B8; \ + VORR V12.B8, V13.B8, V18.B8 + +#define ADVANCE_LOOP(goto_loop) \ + VST3.P [V16.B8, V17.B8, V18.B8], 24(R3); \ + ADD $32, R4; \ + CMP R4, R2; \ + BGT goto_loop + +#define RETURN() \ + SUB R0, R3; \ + SUB R1, R4; \ + MOVD R3, ret+56(FP); \ + MOVD R4, ret1+64(FP); \ + RET + + +// func decodeARM64(dst []byte, src []byte, lut *int8) (int, int) +TEXT ·decodeARM64(SB),NOSPLIT,$0-72 + LOAD_ARGS() + LOAD_ARG_LUT() + LOAD_CONST_LUT() + +loop: + LOAD_INPUT() + + // Compare and normalize the 63rd and 64th characters + COMPARE_INPUT(V0) + UPDATE_INPUT(V5) + COMPARE_INPUT(V1) + UPDATE_INPUT(V6) + + DECODE_INPUT(done) // Detect invalid input characters + ADVANCE_LOOP(loop) // Store results and continue + +done: + RETURN() + + +// func decodeStdARM64(dst []byte, src []byte, lut *int8) (int, int) +TEXT ·decodeStdARM64(SB),NOSPLIT,$0-72 + LOAD_ARGS() + LOAD_CONST_LUT() + +loop: + LOAD_INPUT() + COMPARE_INPUT(V6) // Compare to '+' + DECODE_INPUT(done) // Detect invalid input characters + ADVANCE_LOOP(loop) // Store results and continue + +done: + RETURN() + + +DATA ·mask_lut+0x00(SB)/1, $0xa8 +DATA ·mask_lut+0x01(SB)/1, $0xf8 +DATA ·mask_lut+0x02(SB)/1, $0xf8 +DATA ·mask_lut+0x03(SB)/1, $0xf8 +DATA ·mask_lut+0x04(SB)/1, $0xf8 +DATA ·mask_lut+0x05(SB)/1, $0xf8 +DATA ·mask_lut+0x06(SB)/1, $0xf8 +DATA ·mask_lut+0x07(SB)/1, $0xf8 +DATA ·mask_lut+0x08(SB)/1, $0xf8 +DATA ·mask_lut+0x09(SB)/1, $0xf8 +DATA ·mask_lut+0x0a(SB)/1, $0xf0 +DATA ·mask_lut+0x0b(SB)/1, $0x54 +DATA ·mask_lut+0x0c(SB)/1, $0x50 +DATA ·mask_lut+0x0d(SB)/1, $0x50 +DATA ·mask_lut+0x0e(SB)/1, $0x50 +DATA ·mask_lut+0x0f(SB)/1, $0x54 +GLOBL ·mask_lut(SB), NOPTR|RODATA, $16 + +DATA ·bpos_lut+0x00(SB)/1, $0x01 +DATA ·bpos_lut+0x01(SB)/1, $0x02 +DATA ·bpos_lut+0x02(SB)/1, $0x04 +DATA ·bpos_lut+0x03(SB)/1, $0x08 +DATA ·bpos_lut+0x04(SB)/1, $0x10 +DATA ·bpos_lut+0x05(SB)/1, $0x20 +DATA ·bpos_lut+0x06(SB)/1, $0x40 +DATA ·bpos_lut+0x07(SB)/1, $0x80 +DATA ·bpos_lut+0x08(SB)/1, $0x00 +DATA ·bpos_lut+0x09(SB)/1, $0x00 +DATA ·bpos_lut+0x0a(SB)/1, $0x00 +DATA ·bpos_lut+0x0b(SB)/1, $0x00 +DATA ·bpos_lut+0x0c(SB)/1, $0x00 +DATA ·bpos_lut+0x0d(SB)/1, $0x00 +DATA ·bpos_lut+0x0e(SB)/1, $0x00 +DATA ·bpos_lut+0x0f(SB)/1, $0x00 +GLOBL ·bpos_lut(SB), NOPTR|RODATA, $16 + +DATA ·shft_lut+0x00(SB)/1, $0x00 +DATA ·shft_lut+0x01(SB)/1, $0x00 +DATA ·shft_lut+0x02(SB)/1, $0x13 +DATA ·shft_lut+0x03(SB)/1, $0x04 +DATA ·shft_lut+0x04(SB)/1, $0xbf +DATA ·shft_lut+0x05(SB)/1, $0xbf +DATA ·shft_lut+0x06(SB)/1, $0xb9 +DATA ·shft_lut+0x07(SB)/1, $0xb9 +DATA ·shft_lut+0x08(SB)/1, $0x00 +DATA ·shft_lut+0x09(SB)/1, $0x00 +DATA ·shft_lut+0x0a(SB)/1, $0x00 +DATA ·shft_lut+0x0b(SB)/1, $0x00 +DATA ·shft_lut+0x0c(SB)/1, $0x00 +DATA ·shft_lut+0x0d(SB)/1, $0x00 +DATA ·shft_lut+0x0e(SB)/1, $0x00 +DATA ·shft_lut+0x0f(SB)/1, $0x00 +GLOBL ·shft_lut(SB), NOPTR|RODATA, $16 diff --git a/vendor/github.com/segmentio/asm/base64/encode_amd64.go b/vendor/github.com/segmentio/asm/base64/encode_amd64.go new file mode 100644 index 0000000000..a83c81f157 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_amd64.go @@ -0,0 +1,7 @@ +// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT. + +//go:build !purego + +package base64 + +func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/encode_amd64.s b/vendor/github.com/segmentio/asm/base64/encode_amd64.s new file mode 100644 index 0000000000..6797c977e8 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_amd64.s @@ -0,0 +1,87 @@ +// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT. + +//go:build !purego + +#include "textflag.h" + +// func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int) +// Requires: AVX, AVX2, SSE4.1 +TEXT ·encodeAVX2(SB), NOSPLIT, $0-72 + MOVQ dst_base+0(FP), AX + MOVQ src_base+24(FP), DX + MOVQ lut+48(FP), SI + MOVQ src_len+32(FP), DI + MOVB $0x33, CL + PINSRB $0x00, CX, X4 + VPBROADCASTB X4, Y4 + MOVB $0x19, CL + PINSRB $0x00, CX, X5 + VPBROADCASTB X5, Y5 + XORQ CX, CX + XORQ BX, BX + + // Load the 16-byte LUT into both lanes of the register + VPERMQ $0x44, (SI), Y3 + + // Load the first block using a mask to avoid potential fault + VMOVDQU b64_enc_load<>+0(SB), Y0 + VPMASKMOVD -4(DX)(BX*1), Y0, Y0 + +loop: + VPSHUFB b64_enc_shuf<>+0(SB), Y0, Y0 + VPAND b64_enc_mask1<>+0(SB), Y0, Y1 + VPSLLW $0x08, Y1, Y2 + VPSLLW $0x04, Y1, Y1 + VPBLENDW $0xaa, Y2, Y1, Y2 + VPAND b64_enc_mask2<>+0(SB), Y0, Y1 + VPMULHUW b64_enc_mult<>+0(SB), Y1, Y0 + VPOR Y0, Y2, Y0 + VPSUBUSB Y4, Y0, Y1 + VPCMPGTB Y5, Y0, Y2 + VPSUBB Y2, Y1, Y1 + VPSHUFB Y1, Y3, Y1 + VPADDB Y0, Y1, Y0 + VMOVDQU Y0, (AX)(CX*1) + ADDQ $0x20, CX + ADDQ $0x18, BX + SUBQ $0x18, DI + CMPQ DI, $0x20 + JB done + VMOVDQU -4(DX)(BX*1), Y0 + JMP loop + +done: + MOVQ CX, ret+56(FP) + MOVQ BX, ret1+64(FP) + VZEROUPPER + RET + +DATA b64_enc_load<>+0(SB)/8, $0x8000000000000000 +DATA b64_enc_load<>+8(SB)/8, $0x8000000080000000 +DATA b64_enc_load<>+16(SB)/8, $0x8000000080000000 +DATA b64_enc_load<>+24(SB)/8, $0x8000000080000000 +GLOBL b64_enc_load<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_shuf<>+0(SB)/8, $0x0809070805060405 +DATA b64_enc_shuf<>+8(SB)/8, $0x0e0f0d0e0b0c0a0b +DATA b64_enc_shuf<>+16(SB)/8, $0x0405030401020001 +DATA b64_enc_shuf<>+24(SB)/8, $0x0a0b090a07080607 +GLOBL b64_enc_shuf<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_mask1<>+0(SB)/8, $0x003f03f0003f03f0 +DATA b64_enc_mask1<>+8(SB)/8, $0x003f03f0003f03f0 +DATA b64_enc_mask1<>+16(SB)/8, $0x003f03f0003f03f0 +DATA b64_enc_mask1<>+24(SB)/8, $0x003f03f0003f03f0 +GLOBL b64_enc_mask1<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_mask2<>+0(SB)/8, $0x0fc0fc000fc0fc00 +DATA b64_enc_mask2<>+8(SB)/8, $0x0fc0fc000fc0fc00 +DATA b64_enc_mask2<>+16(SB)/8, $0x0fc0fc000fc0fc00 +DATA b64_enc_mask2<>+24(SB)/8, $0x0fc0fc000fc0fc00 +GLOBL b64_enc_mask2<>(SB), RODATA|NOPTR, $32 + +DATA b64_enc_mult<>+0(SB)/8, $0x0400004004000040 +DATA b64_enc_mult<>+8(SB)/8, $0x0400004004000040 +DATA b64_enc_mult<>+16(SB)/8, $0x0400004004000040 +DATA b64_enc_mult<>+24(SB)/8, $0x0400004004000040 +GLOBL b64_enc_mult<>(SB), RODATA|NOPTR, $32 diff --git a/vendor/github.com/segmentio/asm/base64/encode_arm64.go b/vendor/github.com/segmentio/asm/base64/encode_arm64.go new file mode 100644 index 0000000000..b6a3814928 --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_arm64.go @@ -0,0 +1,6 @@ +//go:build !purego +// +build !purego + +package base64 + +func encodeARM64(dst []byte, src []byte, lut *int8) (int, int) diff --git a/vendor/github.com/segmentio/asm/base64/encode_arm64.s b/vendor/github.com/segmentio/asm/base64/encode_arm64.s new file mode 100644 index 0000000000..4654313bbd --- /dev/null +++ b/vendor/github.com/segmentio/asm/base64/encode_arm64.s @@ -0,0 +1,97 @@ +#include "textflag.h" + +#define Rdst R0 +#define Rsrc R1 +#define Rlen R2 +#define Rwr R3 +#define Rrem R4 +#define Rtmp R5 + +#define Vlut V0 +#define Vfld0 V6 +#define Vfld1 V7 +#define Vfld2 V8 +#define Vfld3 V9 +#define Vsrc0 V10 +#define Vsrc1 V11 +#define Vsrc2 V12 +#define Vr0a V13 +#define Vr1a V14 +#define Vr2a V15 +#define Vr3a V16 +#define Vr0b V17 +#define Vr1b V18 +#define Vr2b V19 +#define Vr3b V20 + +// func encodeARM64(dst []byte, src []byte, lut *int8) (int, int) +TEXT ·encodeARM64(SB),NOSPLIT,$0-72 + // Load dst/src info + MOVD dst_base+0(FP), Rdst + MOVD src_base+24(FP), Rsrc + MOVD src_len+32(FP), Rlen + MOVD lut+48(FP), Rtmp + VLD1 (Rtmp), [Vlut.B16] + + MOVD Rlen, Rrem + MOVD Rdst, Rwr + + VMOVI $51, V1.B16 + VMOVI $26, V2.B16 + VMOVI $63, V3.B16 + VMOVI $13, V4.B16 + +loop: + VLD3.P 48(Rsrc), [Vsrc0.B16, Vsrc1.B16, Vsrc2.B16] + + // Split 3 source blocks into 4 lookup inputs + VUSHR $2, Vsrc0.B16, Vfld0.B16 + VUSHR $4, Vsrc1.B16, Vfld1.B16 + VUSHR $6, Vsrc2.B16, Vfld2.B16 + VSHL $4, Vsrc0.B16, Vsrc0.B16 + VSHL $2, Vsrc1.B16, Vsrc1.B16 + VORR Vsrc0.B16, Vfld1.B16, Vfld1.B16 + VORR Vsrc1.B16, Vfld2.B16, Vfld2.B16 + VAND V3.B16, Vfld1.B16, Vfld1.B16 + VAND V3.B16, Vfld2.B16, Vfld2.B16 + VAND V3.B16, Vsrc2.B16, Vfld3.B16 + + WORD $0x6e212ccd // VUQSUB V1.B16, Vfld0.B16, Vr0a.B16 + WORD $0x4e263451 // VCMGT V2.B16, Vfld0.B16, Vr0b.B16 + VAND V4.B16, Vr0b.B16, Vr0b.B16 + VORR Vr0b.B16, Vr0a.B16, Vr0a.B16 + WORD $0x6e212cee // VUQSUB V1.B16, Vfld1.B16, Vr1a.B16 + WORD $0x4e273452 // VCMGT V2.B16, Vfld1.B16, Vr1b.B16 + VAND V4.B16, Vr1b.B16, Vr1b.B16 + VORR Vr1b.B16, Vr1a.B16, Vr1a.B16 + WORD $0x6e212d0f // VUQSUB V1.B16, Vfld2.B16, Vr2a.B16 + WORD $0x4e283453 // VCMGT V2.B16, Vfld2.B16, Vr2b.B16 + VAND V4.B16, Vr2b.B16, Vr2b.B16 + VORR Vr2b.B16, Vr2a.B16, Vr2a.B16 + WORD $0x6e212d30 // VUQSUB V1.B16, Vfld3.B16, Vr3a.B16 + WORD $0x4e293454 // VCMGT V2.B16, Vfld3.B16, Vr3b.B16 + VAND V4.B16, Vr3b.B16, Vr3b.B16 + VORR Vr3b.B16, Vr3a.B16, Vr3a.B16 + + // Add result of lookup table to each field + VTBL Vr0a.B16, [Vlut.B16], Vr0a.B16 + VADD Vr0a.B16, Vfld0.B16, Vfld0.B16 + VTBL Vr1a.B16, [Vlut.B16], Vr1a.B16 + VADD Vr1a.B16, Vfld1.B16, Vfld1.B16 + VTBL Vr2a.B16, [Vlut.B16], Vr2a.B16 + VADD Vr2a.B16, Vfld2.B16, Vfld2.B16 + VTBL Vr3a.B16, [Vlut.B16], Vr3a.B16 + VADD Vr3a.B16, Vfld3.B16, Vfld3.B16 + + VST4.P [Vfld0.B16, Vfld1.B16, Vfld2.B16, Vfld3.B16], 64(Rwr) + SUB $48, Rrem + CMP $48, Rrem + BGE loop + +done: + SUB Rdst, Rwr + SUB Rrem, Rlen + MOVD Rwr, ret+56(FP) + MOVD Rlen, ret1+64(FP) + RET + diff --git a/vendor/github.com/segmentio/asm/cpu/arm/arm.go b/vendor/github.com/segmentio/asm/cpu/arm/arm.go new file mode 100644 index 0000000000..47c695a075 --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/arm/arm.go @@ -0,0 +1,80 @@ +package arm + +import ( + "github.com/segmentio/asm/cpu/cpuid" + . "golang.org/x/sys/cpu" +) + +type CPU cpuid.CPU + +func (cpu CPU) Has(feature Feature) bool { + return cpuid.CPU(cpu).Has(cpuid.Feature(feature)) +} + +func (cpu *CPU) set(feature Feature, enable bool) { + (*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable) +} + +type Feature cpuid.Feature + +const ( + SWP Feature = 1 << iota // SWP instruction support + HALF // Half-word load and store support + THUMB // ARM Thumb instruction set + BIT26 // Address space limited to 26-bits + FASTMUL // 32-bit operand, 64-bit result multiplication support + FPA // Floating point arithmetic support + VFP // Vector floating point support + EDSP // DSP Extensions support + JAVA // Java instruction set + IWMMXT // Intel Wireless MMX technology support + CRUNCH // MaverickCrunch context switching and handling + THUMBEE // Thumb EE instruction set + NEON // NEON instruction set + VFPv3 // Vector floating point version 3 support + VFPv3D16 // Vector floating point version 3 D8-D15 + TLS // Thread local storage support + VFPv4 // Vector floating point version 4 support + IDIVA // Integer divide instruction support in ARM mode + IDIVT // Integer divide instruction support in Thumb mode + VFPD32 // Vector floating point version 3 D15-D31 + LPAE // Large Physical Address Extensions + EVTSTRM // Event stream support + AES // AES hardware implementation + PMULL // Polynomial multiplication instruction set + SHA1 // SHA1 hardware implementation + SHA2 // SHA2 hardware implementation + CRC32 // CRC32 hardware implementation +) + +func ABI() CPU { + cpu := CPU(0) + cpu.set(SWP, ARM.HasSWP) + cpu.set(HALF, ARM.HasHALF) + cpu.set(THUMB, ARM.HasTHUMB) + cpu.set(BIT26, ARM.Has26BIT) + cpu.set(FASTMUL, ARM.HasFASTMUL) + cpu.set(FPA, ARM.HasFPA) + cpu.set(VFP, ARM.HasVFP) + cpu.set(EDSP, ARM.HasEDSP) + cpu.set(JAVA, ARM.HasJAVA) + cpu.set(IWMMXT, ARM.HasIWMMXT) + cpu.set(CRUNCH, ARM.HasCRUNCH) + cpu.set(THUMBEE, ARM.HasTHUMBEE) + cpu.set(NEON, ARM.HasNEON) + cpu.set(VFPv3, ARM.HasVFPv3) + cpu.set(VFPv3D16, ARM.HasVFPv3D16) + cpu.set(TLS, ARM.HasTLS) + cpu.set(VFPv4, ARM.HasVFPv4) + cpu.set(IDIVA, ARM.HasIDIVA) + cpu.set(IDIVT, ARM.HasIDIVT) + cpu.set(VFPD32, ARM.HasVFPD32) + cpu.set(LPAE, ARM.HasLPAE) + cpu.set(EVTSTRM, ARM.HasEVTSTRM) + cpu.set(AES, ARM.HasAES) + cpu.set(PMULL, ARM.HasPMULL) + cpu.set(SHA1, ARM.HasSHA1) + cpu.set(SHA2, ARM.HasSHA2) + cpu.set(CRC32, ARM.HasCRC32) + return cpu +} diff --git a/vendor/github.com/segmentio/asm/cpu/arm64/arm64.go b/vendor/github.com/segmentio/asm/cpu/arm64/arm64.go new file mode 100644 index 0000000000..0c5134c76e --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/arm64/arm64.go @@ -0,0 +1,74 @@ +package arm64 + +import ( + "github.com/segmentio/asm/cpu/cpuid" + . "golang.org/x/sys/cpu" +) + +type CPU cpuid.CPU + +func (cpu CPU) Has(feature Feature) bool { + return cpuid.CPU(cpu).Has(cpuid.Feature(feature)) +} + +func (cpu *CPU) set(feature Feature, enable bool) { + (*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable) +} + +type Feature cpuid.Feature + +const ( + FP Feature = 1 << iota // Floating-point instruction set (always available) + ASIMD // Advanced SIMD (always available) + EVTSTRM // Event stream support + AES // AES hardware implementation + PMULL // Polynomial multiplication instruction set + SHA1 // SHA1 hardware implementation + SHA2 // SHA2 hardware implementation + CRC32 // CRC32 hardware implementation + ATOMICS // Atomic memory operation instruction set + FPHP // Half precision floating-point instruction set + ASIMDHP // Advanced SIMD half precision instruction set + CPUID // CPUID identification scheme registers + ASIMDRDM // Rounding double multiply add/subtract instruction set + JSCVT // Javascript conversion from floating-point to integer + FCMA // Floating-point multiplication and addition of complex numbers + LRCPC // Release Consistent processor consistent support + DCPOP // Persistent memory support + SHA3 // SHA3 hardware implementation + SM3 // SM3 hardware implementation + SM4 // SM4 hardware implementation + ASIMDDP // Advanced SIMD double precision instruction set + SHA512 // SHA512 hardware implementation + SVE // Scalable Vector Extensions + ASIMDFHM // Advanced SIMD multiplication FP16 to FP32 +) + +func ABI() CPU { + cpu := CPU(0) + cpu.set(FP, ARM64.HasFP) + cpu.set(ASIMD, ARM64.HasASIMD) + cpu.set(EVTSTRM, ARM64.HasEVTSTRM) + cpu.set(AES, ARM64.HasAES) + cpu.set(PMULL, ARM64.HasPMULL) + cpu.set(SHA1, ARM64.HasSHA1) + cpu.set(SHA2, ARM64.HasSHA2) + cpu.set(CRC32, ARM64.HasCRC32) + cpu.set(ATOMICS, ARM64.HasATOMICS) + cpu.set(FPHP, ARM64.HasFPHP) + cpu.set(ASIMDHP, ARM64.HasASIMDHP) + cpu.set(CPUID, ARM64.HasCPUID) + cpu.set(ASIMDRDM, ARM64.HasASIMDRDM) + cpu.set(JSCVT, ARM64.HasJSCVT) + cpu.set(FCMA, ARM64.HasFCMA) + cpu.set(LRCPC, ARM64.HasLRCPC) + cpu.set(DCPOP, ARM64.HasDCPOP) + cpu.set(SHA3, ARM64.HasSHA3) + cpu.set(SM3, ARM64.HasSM3) + cpu.set(SM4, ARM64.HasSM4) + cpu.set(ASIMDDP, ARM64.HasASIMDDP) + cpu.set(SHA512, ARM64.HasSHA512) + cpu.set(SVE, ARM64.HasSVE) + cpu.set(ASIMDFHM, ARM64.HasASIMDFHM) + return cpu +} diff --git a/vendor/github.com/segmentio/asm/cpu/cpu.go b/vendor/github.com/segmentio/asm/cpu/cpu.go new file mode 100644 index 0000000000..6ddf4973f5 --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/cpu.go @@ -0,0 +1,22 @@ +// Pakage cpu provides APIs to detect CPU features available at runtime. +package cpu + +import ( + "github.com/segmentio/asm/cpu/arm" + "github.com/segmentio/asm/cpu/arm64" + "github.com/segmentio/asm/cpu/x86" +) + +var ( + // X86 is the bitset representing the set of the x86 instruction sets are + // supported by the CPU. + X86 = x86.ABI() + + // ARM is the bitset representing which parts of the arm instruction sets + // are supported by the CPU. + ARM = arm.ABI() + + // ARM64 is the bitset representing which parts of the arm64 instruction + // sets are supported by the CPU. + ARM64 = arm64.ABI() +) diff --git a/vendor/github.com/segmentio/asm/cpu/cpuid/cpuid.go b/vendor/github.com/segmentio/asm/cpu/cpuid/cpuid.go new file mode 100644 index 0000000000..0949d3d584 --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/cpuid/cpuid.go @@ -0,0 +1,32 @@ +// Package cpuid provides generic types used to represent CPU features supported +// by the architecture. +package cpuid + +// CPU is a bitset of feature flags representing the capabilities of various CPU +// architeectures that this package provides optimized assembly routines for. +// +// The intent is to provide a stable ABI between the Go code that generate the +// assembly, and the program that uses the library functions. +type CPU uint64 + +// Feature represents a single CPU feature. +type Feature uint64 + +const ( + // None is a Feature value that has no CPU features enabled. + None Feature = 0 + // All is a Feature value that has all CPU features enabled. + All Feature = 0xFFFFFFFFFFFFFFFF +) + +func (cpu CPU) Has(feature Feature) bool { + return (Feature(cpu) & feature) == feature +} + +func (cpu *CPU) Set(feature Feature, enabled bool) { + if enabled { + *cpu |= CPU(feature) + } else { + *cpu &= ^CPU(feature) + } +} diff --git a/vendor/github.com/segmentio/asm/cpu/x86/x86.go b/vendor/github.com/segmentio/asm/cpu/x86/x86.go new file mode 100644 index 0000000000..9e93537583 --- /dev/null +++ b/vendor/github.com/segmentio/asm/cpu/x86/x86.go @@ -0,0 +1,76 @@ +package x86 + +import ( + "github.com/segmentio/asm/cpu/cpuid" + . "golang.org/x/sys/cpu" +) + +type CPU cpuid.CPU + +func (cpu CPU) Has(feature Feature) bool { + return cpuid.CPU(cpu).Has(cpuid.Feature(feature)) +} + +func (cpu *CPU) set(feature Feature, enable bool) { + (*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable) +} + +type Feature cpuid.Feature + +const ( + SSE Feature = 1 << iota // SSE functions + SSE2 // P4 SSE functions + SSE3 // Prescott SSE3 functions + SSE41 // Penryn SSE4.1 functions + SSE42 // Nehalem SSE4.2 functions + SSE4A // AMD Barcelona microarchitecture SSE4a instructions + SSSE3 // Conroe SSSE3 functions + AVX // AVX functions + AVX2 // AVX2 functions + AVX512BF16 // AVX-512 BFLOAT16 Instructions + AVX512BITALG // AVX-512 Bit Algorithms + AVX512BW // AVX-512 Byte and Word Instructions + AVX512CD // AVX-512 Conflict Detection Instructions + AVX512DQ // AVX-512 Doubleword and Quadword Instructions + AVX512ER // AVX-512 Exponential and Reciprocal Instructions + AVX512F // AVX-512 Foundation + AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions + AVX512PF // AVX-512 Prefetch Instructions + AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions + AVX512VBMI2 // AVX-512 Vector Bit Manipulation Instructions, Version 2 + AVX512VL // AVX-512 Vector Length Extensions + AVX512VNNI // AVX-512 Vector Neural Network Instructions + AVX512VP2INTERSECT // AVX-512 Intersect for D/Q + AVX512VPOPCNTDQ // AVX-512 Vector Population Count Doubleword and Quadword + CMOV // Conditional move +) + +func ABI() CPU { + cpu := CPU(0) + cpu.set(SSE, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have SEE? + cpu.set(SSE2, X86.HasSSE2) + cpu.set(SSE3, X86.HasSSE3) + cpu.set(SSE41, X86.HasSSE41) + cpu.set(SSE42, X86.HasSSE42) + cpu.set(SSE4A, false) // TODO: add upstream support in golang.org/x/sys/cpu? + cpu.set(SSSE3, X86.HasSSSE3) + cpu.set(AVX, X86.HasAVX) + cpu.set(AVX2, X86.HasAVX2) + cpu.set(AVX512BF16, X86.HasAVX512BF16) + cpu.set(AVX512BITALG, X86.HasAVX512BITALG) + cpu.set(AVX512BW, X86.HasAVX512BW) + cpu.set(AVX512CD, X86.HasAVX512CD) + cpu.set(AVX512DQ, X86.HasAVX512DQ) + cpu.set(AVX512ER, X86.HasAVX512ER) + cpu.set(AVX512F, X86.HasAVX512F) + cpu.set(AVX512IFMA, X86.HasAVX512IFMA) + cpu.set(AVX512PF, X86.HasAVX512PF) + cpu.set(AVX512VBMI, X86.HasAVX512VBMI) + cpu.set(AVX512VBMI2, X86.HasAVX512VBMI2) + cpu.set(AVX512VL, X86.HasAVX512VL) + cpu.set(AVX512VNNI, X86.HasAVX512VNNI) + cpu.set(AVX512VP2INTERSECT, false) // TODO: add upstream support in golang.org/x/sys/cpu? + cpu.set(AVX512VPOPCNTDQ, X86.HasAVX512VPOPCNTDQ) + cpu.set(CMOV, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have CMOV? + return cpu +} diff --git a/vendor/github.com/segmentio/asm/internal/unsafebytes/unsafebytes.go b/vendor/github.com/segmentio/asm/internal/unsafebytes/unsafebytes.go new file mode 100644 index 0000000000..913c9cc68b --- /dev/null +++ b/vendor/github.com/segmentio/asm/internal/unsafebytes/unsafebytes.go @@ -0,0 +1,20 @@ +package unsafebytes + +import "unsafe" + +func Pointer(b []byte) *byte { + return *(**byte)(unsafe.Pointer(&b)) +} + +func String(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func BytesOf(s string) []byte { + return *(*[]byte)(unsafe.Pointer(&sliceHeader{str: s, cap: len(s)})) +} + +type sliceHeader struct { + str string + cap int +} diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go index 915d5090dd..08c36e74f4 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go @@ -1146,13 +1146,28 @@ func (dmp *DiffMatchPatch) DiffPrettyText(diffs []Diff) string { switch diff.Type { case DiffInsert: - _, _ = buff.WriteString("\x1b[32m") - _, _ = buff.WriteString(text) - _, _ = buff.WriteString("\x1b[0m") + lines := strings.Split(text, "\n") + for i, line := range lines { + _, _ = buff.WriteString("\x1b[32m") + _, _ = buff.WriteString(line) + if i < len(lines)-1 { + _, _ = buff.WriteString("\x1b[0m\n") + } else { + _, _ = buff.WriteString("\x1b[0m") + } + } + case DiffDelete: - _, _ = buff.WriteString("\x1b[31m") - _, _ = buff.WriteString(text) - _, _ = buff.WriteString("\x1b[0m") + lines := strings.Split(text, "\n") + for i, line := range lines { + _, _ = buff.WriteString("\x1b[31m") + _, _ = buff.WriteString(line) + if i < len(lines)-1 { + _, _ = buff.WriteString("\x1b[0m\n") + } else { + _, _ = buff.WriteString("\x1b[0m") + } + } case DiffEqual: _, _ = buff.WriteString(text) } @@ -1305,7 +1320,6 @@ func (dmp *DiffMatchPatch) DiffFromDelta(text1 string, delta string) (diffs []Di // diffLinesToStrings splits two texts into a list of strings. Each string represents one line. func (dmp *DiffMatchPatch) diffLinesToStrings(text1, text2 string) (string, string, []string) { - // '\x00' is a valid character, but various debuggers don't like it. So we'll insert a junk entry to avoid generating a null character. lineArray := []string{""} // e.g. lineArray[4] == 'Hello\n' lineHash := make(map[string]int) @@ -1316,12 +1330,11 @@ func (dmp *DiffMatchPatch) diffLinesToStrings(text1, text2 string) (string, stri return intArrayToString(strIndexArray1), intArrayToString(strIndexArray2), lineArray } -// diffLinesToStringsMunge splits a text into an array of strings, and reduces the texts to a []string. -func (dmp *DiffMatchPatch) diffLinesToStringsMunge(text string, lineArray *[]string, lineHash map[string]int) []uint32 { - // Walk the text, pulling out a substring for each line. text.split('\n') would would temporarily double our memory footprint. Modifying text would create many large strings to garbage collect. +// diffLinesToStringsMunge splits a text into an array of strings, and reduces the texts to a []index. +func (dmp *DiffMatchPatch) diffLinesToStringsMunge(text string, lineArray *[]string, lineHash map[string]int) []index { lineStart := 0 lineEnd := -1 - strs := []uint32{} + strs := []index{} for lineEnd < len(text)-1 { lineEnd = indexOf(text, "\n", lineStart) @@ -1335,11 +1348,11 @@ func (dmp *DiffMatchPatch) diffLinesToStringsMunge(text string, lineArray *[]str lineValue, ok := lineHash[line] if ok { - strs = append(strs, uint32(lineValue)) + strs = append(strs, index(lineValue)) } else { *lineArray = append(*lineArray, line) lineHash[line] = len(*lineArray) - 1 - strs = append(strs, uint32(len(*lineArray)-1)) + strs = append(strs, index(len(*lineArray)-1)) } } diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/index.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/index.go new file mode 100644 index 0000000000..965a1c64bd --- /dev/null +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/index.go @@ -0,0 +1,32 @@ +package diffmatchpatch + +type index uint32 + +const runeSkipStart = 0xd800 +const runeSkipEnd = 0xdfff + 1 +const runeMax = 0x110000 // next invalid code point + +func stringToIndex(text string) []index { + runes := []rune(text) + indexes := make([]index, len(runes)) + for i, r := range runes { + if r < runeSkipEnd { + indexes[i] = index(r) + } else { + indexes[i] = index(r) - (runeSkipEnd - runeSkipStart) + } + } + return indexes +} + +func indexesToString(indexes []index) string { + runes := make([]rune, len(indexes)) + for i, index := range indexes { + if index < runeSkipStart { + runes[i] = rune(index) + } else { + runes[i] = rune(index + (runeSkipEnd - runeSkipStart)) + } + } + return string(runes) +} diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go index eb727bb594..573b6bf751 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go @@ -93,14 +93,14 @@ func runesIndex(r1, r2 []rune) int { return -1 } -func intArrayToString(ns []uint32) string { +func intArrayToString(ns []index) string { if len(ns) == 0 { return "" } b := []rune{} for _, n := range ns { - b = append(b, intToRune(n)) + b = append(b, intToRune(uint32(n))) } return string(b) } diff --git a/vendor/github.com/tchap/go-patricia/v2/patricia/patricia.go b/vendor/github.com/tchap/go-patricia/v2/patricia/patricia.go index 7b9975e383..9bf8f4fec5 100644 --- a/vendor/github.com/tchap/go-patricia/v2/patricia/patricia.go +++ b/vendor/github.com/tchap/go-patricia/v2/patricia/patricia.go @@ -465,7 +465,7 @@ func (trie *Trie) compact() *Trie { // If any item is set, we cannot compact since we want to retain // the ability to do searching by key. This makes compaction less usable, // but that simply cannot be avoided. - if trie.item != nil || child.item != nil { + if child == nil || trie.item != nil || child.item != nil { return trie } diff --git a/vendor/github.com/valyala/fastjson/.gitignore b/vendor/github.com/valyala/fastjson/.gitignore new file mode 100644 index 0000000000..6e92f57d46 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/.gitignore @@ -0,0 +1 @@ +tags diff --git a/vendor/github.com/valyala/fastjson/.travis.yml b/vendor/github.com/valyala/fastjson/.travis.yml new file mode 100644 index 0000000000..472a82190c --- /dev/null +++ b/vendor/github.com/valyala/fastjson/.travis.yml @@ -0,0 +1,19 @@ +language: go + +go: + - 1.10.x + +script: + # build test for supported platforms + - GOOS=linux go build + - GOOS=darwin go build + - GOOS=freebsd go build + - GOOS=windows go build + + # run tests on a standard platform + - go test -v ./... -coverprofile=coverage.txt -covermode=atomic + - go test -v ./... -race + +after_success: + # Upload coverage results to codecov.io + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE.libyaml b/vendor/github.com/valyala/fastjson/LICENSE similarity index 50% rename from vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE.libyaml rename to vendor/github.com/valyala/fastjson/LICENSE index 8da58fbf6f..6f665f3e29 100644 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE.libyaml +++ b/vendor/github.com/valyala/fastjson/LICENSE @@ -1,23 +1,13 @@ -The following files were ported to Go from C files of libyaml, and thus -are still covered by their original copyright and license: +The MIT License (MIT) - apic.go - emitterc.go - parserc.go - readerc.go - scannerc.go - writerc.go - yamlh.go - yamlprivateh.go +Copyright (c) 2018 Aliaksandr Valialkin -Copyright (c) 2006 Kirill Simonov - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -29,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/vendor/github.com/valyala/fastjson/README.md b/vendor/github.com/valyala/fastjson/README.md new file mode 100644 index 0000000000..f32c693937 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/README.md @@ -0,0 +1,227 @@ +[![Build Status](https://travis-ci.org/valyala/fastjson.svg)](https://travis-ci.org/valyala/fastjson) +[![GoDoc](https://godoc.org/github.com/valyala/fastjson?status.svg)](http://godoc.org/github.com/valyala/fastjson) +[![Go Report](https://goreportcard.com/badge/github.com/valyala/fastjson)](https://goreportcard.com/report/github.com/valyala/fastjson) +[![codecov](https://codecov.io/gh/valyala/fastjson/branch/master/graph/badge.svg)](https://codecov.io/gh/valyala/fastjson) + +# fastjson - fast JSON parser and validator for Go + + +## Features + + * Fast. As usual, up to 15x faster than the standard [encoding/json](https://golang.org/pkg/encoding/json/). + See [benchmarks](#benchmarks). + * Parses arbitrary JSON without schema, reflection, struct magic and code generation + contrary to [easyjson](https://github.com/mailru/easyjson). + * Provides simple [API](http://godoc.org/github.com/valyala/fastjson). + * Outperforms [jsonparser](https://github.com/buger/jsonparser) and [gjson](https://github.com/tidwall/gjson) + when accessing multiple unrelated fields, since `fastjson` parses the input JSON only once. + * Validates the parsed JSON unlike [jsonparser](https://github.com/buger/jsonparser) + and [gjson](https://github.com/tidwall/gjson). + * May quickly extract a part of the original JSON with `Value.Get(...).MarshalTo` and modify it + with [Del](https://godoc.org/github.com/valyala/fastjson#Value.Del) + and [Set](https://godoc.org/github.com/valyala/fastjson#Value.Set) functions. + * May parse array containing values with distinct types (aka non-homogenous types). + For instance, `fastjson` easily parses the following JSON array `[123, "foo", [456], {"k": "v"}, null]`. + * `fastjson` preserves the original order of object items when calling + [Object.Visit](https://godoc.org/github.com/valyala/fastjson#Object.Visit). + + +## Known limitations + + * Requies extra care to work with - references to certain objects recursively + returned by [Parser](https://godoc.org/github.com/valyala/fastjson#Parser) + must be released before the next call to [Parse](https://godoc.org/github.com/valyala/fastjson#Parser.Parse). + Otherwise the program may work improperly. The same applies to objects returned by [Arena](https://godoc.org/github.com/valyala/fastjson#Arena). + Adhere recommendations from [docs](https://godoc.org/github.com/valyala/fastjson). + * Cannot parse JSON from `io.Reader`. There is [Scanner](https://godoc.org/github.com/valyala/fastjson#Scanner) + for parsing stream of JSON values from a string. + + +## Usage + +One-liner accessing a single field: +```go + s := []byte(`{"foo": [123, "bar"]}`) + fmt.Printf("foo.0=%d\n", fastjson.GetInt(s, "foo", "0")) + + // Output: + // foo.0=123 +``` + +Accessing multiple fields with error handling: +```go + var p fastjson.Parser + v, err := p.Parse(`{ + "str": "bar", + "int": 123, + "float": 1.23, + "bool": true, + "arr": [1, "foo", {}] + }`) + if err != nil { + log.Fatal(err) + } + fmt.Printf("foo=%s\n", v.GetStringBytes("str")) + fmt.Printf("int=%d\n", v.GetInt("int")) + fmt.Printf("float=%f\n", v.GetFloat64("float")) + fmt.Printf("bool=%v\n", v.GetBool("bool")) + fmt.Printf("arr.1=%s\n", v.GetStringBytes("arr", "1")) + + // Output: + // foo=bar + // int=123 + // float=1.230000 + // bool=true + // arr.1=foo +``` + +See also [examples](https://godoc.org/github.com/valyala/fastjson#pkg-examples). + + +## Security + + * `fastjson` shouldn't crash or panic when parsing input strings specially crafted + by an attacker. It must return error on invalid input JSON. + * `fastjson` requires up to `sizeof(Value) * len(inputJSON)` bytes of memory + for parsing `inputJSON` string. Limit the maximum size of the `inputJSON` + before parsing it in order to limit the maximum memory usage. + + +## Performance optimization tips + + * Re-use [Parser](https://godoc.org/github.com/valyala/fastjson#Parser) and [Scanner](https://godoc.org/github.com/valyala/fastjson#Scanner) + for parsing many JSONs. This reduces memory allocations overhead. + [ParserPool](https://godoc.org/github.com/valyala/fastjson#ParserPool) may be useful in this case. + * Prefer calling `Value.Get*` on the value returned from [Parser](https://godoc.org/github.com/valyala/fastjson#Parser) + instead of calling `Get*` one-liners when multiple fields + must be obtained from JSON, since each `Get*` one-liner re-parses + the input JSON again. + * Prefer calling once [Value.Get](https://godoc.org/github.com/valyala/fastjson#Value.Get) + for common prefix paths and then calling `Value.Get*` on the returned value + for distinct suffix paths. + * Prefer iterating over array returned from [Value.GetArray](https://godoc.org/github.com/valyala/fastjson#Object.Visit) + with a range loop instead of calling `Value.Get*` for each array item. + +## Fuzzing +Install [go-fuzz](https://github.com/dvyukov/go-fuzz) & optionally the go-fuzz-corpus. + +```bash +go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build +``` + +Build using `go-fuzz-build` and run `go-fuzz` with an optional corpus. + +```bash +mkdir -p workdir/corpus +cp $GOPATH/src/github.com/dvyukov/go-fuzz-corpus/json/corpus/* workdir/corpus +go-fuzz-build github.com/valyala/fastjson +go-fuzz -bin=fastjson-fuzz.zip -workdir=workdir +``` + +## Benchmarks + +Go 1.12 has been used for benchmarking. + +Legend: + + * `small` - parse [small.json](testdata/small.json) (190 bytes). + * `medium` - parse [medium.json](testdata/medium.json) (2.3KB). + * `large` - parse [large.json](testdata/large.json) (28KB). + * `canada` - parse [canada.json](testdata/canada.json) (2.2MB). + * `citm` - parse [citm_catalog.json](testdata/citm_catalog.json) (1.7MB). + * `twitter` - parse [twitter.json](testdata/twitter.json) (617KB). + + * `stdjson-map` - parse into a `map[string]interface{}` using `encoding/json`. + * `stdjson-struct` - parse into a struct containing + a subset of fields of the parsed JSON, using `encoding/json`. + * `stdjson-empty-struct` - parse into an empty struct using `encoding/json`. + This is the fastest possible solution for `encoding/json`, may be used + for json validation. See also benchmark results for json validation. + * `fastjson` - parse using `fastjson` without fields access. + * `fastjson-get` - parse using `fastjson` with fields access similar to `stdjson-struct`. + +``` +$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Parse$' +goos: linux +goarch: amd64 +pkg: github.com/valyala/fastjson +BenchmarkParse/small/stdjson-map 200000 7305 ns/op 26.01 MB/s 960 B/op 51 allocs/op +BenchmarkParse/small/stdjson-struct 500000 3431 ns/op 55.37 MB/s 224 B/op 4 allocs/op +BenchmarkParse/small/stdjson-empty-struct 500000 2273 ns/op 83.58 MB/s 168 B/op 2 allocs/op +BenchmarkParse/small/fastjson 5000000 347 ns/op 547.53 MB/s 0 B/op 0 allocs/op +BenchmarkParse/small/fastjson-get 2000000 620 ns/op 306.39 MB/s 0 B/op 0 allocs/op +BenchmarkParse/medium/stdjson-map 30000 40672 ns/op 57.26 MB/s 10196 B/op 208 allocs/op +BenchmarkParse/medium/stdjson-struct 30000 47792 ns/op 48.73 MB/s 9174 B/op 258 allocs/op +BenchmarkParse/medium/stdjson-empty-struct 100000 22096 ns/op 105.40 MB/s 280 B/op 5 allocs/op +BenchmarkParse/medium/fastjson 500000 3025 ns/op 769.90 MB/s 0 B/op 0 allocs/op +BenchmarkParse/medium/fastjson-get 500000 3211 ns/op 725.20 MB/s 0 B/op 0 allocs/op +BenchmarkParse/large/stdjson-map 2000 614079 ns/op 45.79 MB/s 210734 B/op 2785 allocs/op +BenchmarkParse/large/stdjson-struct 5000 298554 ns/op 94.18 MB/s 15616 B/op 353 allocs/op +BenchmarkParse/large/stdjson-empty-struct 5000 268577 ns/op 104.69 MB/s 280 B/op 5 allocs/op +BenchmarkParse/large/fastjson 50000 35210 ns/op 798.56 MB/s 5 B/op 0 allocs/op +BenchmarkParse/large/fastjson-get 50000 35171 ns/op 799.46 MB/s 5 B/op 0 allocs/op +BenchmarkParse/canada/stdjson-map 20 68147307 ns/op 33.03 MB/s 12260502 B/op 392539 allocs/op +BenchmarkParse/canada/stdjson-struct 20 68044518 ns/op 33.08 MB/s 12260123 B/op 392534 allocs/op +BenchmarkParse/canada/stdjson-empty-struct 100 17709250 ns/op 127.11 MB/s 280 B/op 5 allocs/op +BenchmarkParse/canada/fastjson 300 4182404 ns/op 538.22 MB/s 254902 B/op 381 allocs/op +BenchmarkParse/canada/fastjson-get 300 4274744 ns/op 526.60 MB/s 254902 B/op 381 allocs/op +BenchmarkParse/citm/stdjson-map 50 27772612 ns/op 62.19 MB/s 5214163 B/op 95402 allocs/op +BenchmarkParse/citm/stdjson-struct 100 14936191 ns/op 115.64 MB/s 1989 B/op 75 allocs/op +BenchmarkParse/citm/stdjson-empty-struct 100 14946034 ns/op 115.56 MB/s 280 B/op 5 allocs/op +BenchmarkParse/citm/fastjson 1000 1879714 ns/op 918.87 MB/s 17628 B/op 30 allocs/op +BenchmarkParse/citm/fastjson-get 1000 1881598 ns/op 917.94 MB/s 17628 B/op 30 allocs/op +BenchmarkParse/twitter/stdjson-map 100 11289146 ns/op 55.94 MB/s 2187878 B/op 31266 allocs/op +BenchmarkParse/twitter/stdjson-struct 300 5779442 ns/op 109.27 MB/s 408 B/op 6 allocs/op +BenchmarkParse/twitter/stdjson-empty-struct 300 5738504 ns/op 110.05 MB/s 408 B/op 6 allocs/op +BenchmarkParse/twitter/fastjson 2000 774042 ns/op 815.86 MB/s 2541 B/op 2 allocs/op +BenchmarkParse/twitter/fastjson-get 2000 777833 ns/op 811.89 MB/s 2541 B/op 2 allocs/op +``` + +Benchmark results for json validation: + +``` +$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Validate$' +goos: linux +goarch: amd64 +pkg: github.com/valyala/fastjson +BenchmarkValidate/small/stdjson 2000000 955 ns/op 198.83 MB/s 72 B/op 2 allocs/op +BenchmarkValidate/small/fastjson 5000000 384 ns/op 493.60 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/medium/stdjson 200000 10799 ns/op 215.66 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/medium/fastjson 300000 3809 ns/op 611.30 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/large/stdjson 10000 133064 ns/op 211.31 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/large/fastjson 30000 45268 ns/op 621.14 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/canada/stdjson 200 8470904 ns/op 265.74 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/canada/fastjson 500 2973377 ns/op 757.07 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/citm/stdjson 200 7273172 ns/op 237.48 MB/s 184 B/op 5 allocs/op +BenchmarkValidate/citm/fastjson 1000 1684430 ns/op 1025.39 MB/s 0 B/op 0 allocs/op +BenchmarkValidate/twitter/stdjson 500 2849439 ns/op 221.63 MB/s 312 B/op 6 allocs/op +BenchmarkValidate/twitter/fastjson 2000 1036796 ns/op 609.10 MB/s 0 B/op 0 allocs/op +``` + +## FAQ + + * Q: _There are a ton of other high-perf packages for JSON parsing in Go. Why creating yet another package?_ + A: Because other packages require either rigid JSON schema via struct magic + and code generation or perform poorly when multiple unrelated fields + must be obtained from the parsed JSON. + Additionally, `fastjson` provides nicer [API](http://godoc.org/github.com/valyala/fastjson). + + * Q: _What is the main purpose for `fastjson`?_ + A: High-perf JSON parsing for [RTB](https://www.iab.com/wp-content/uploads/2015/05/OpenRTB_API_Specification_Version_2_3_1.pdf) + and other [JSON-RPC](https://en.wikipedia.org/wiki/JSON-RPC) services. + + * Q: _Why fastjson doesn't provide fast marshaling (serialization)?_ + A: Actually it provides some sort of marshaling - see [Value.MarshalTo](https://godoc.org/github.com/valyala/fastjson#Value.MarshalTo). + But I'd recommend using [quicktemplate](https://github.com/valyala/quicktemplate#use-cases) + for high-performance JSON marshaling :) + + * Q: _`fastjson` crashes my program!_ + A: There is high probability of improper use. + * Make sure you don't hold references to objects recursively returned by `Parser` / `Scanner` + beyond the next `Parser.Parse` / `Scanner.Next` call + if such restriction is mentioned in [docs](https://github.com/valyala/fastjson/issues/new). + * Make sure you don't access `fastjson` objects from concurrently running goroutines + if such restriction is mentioned in [docs](https://github.com/valyala/fastjson/issues/new). + * Build and run your program with [-race](https://golang.org/doc/articles/race_detector.html) flag. + Make sure the race detector detects zero races. + * If your program continue crashing after fixing issues mentioned above, [file a bug](https://github.com/valyala/fastjson/issues/new). diff --git a/vendor/github.com/valyala/fastjson/arena.go b/vendor/github.com/valyala/fastjson/arena.go new file mode 100644 index 0000000000..9fe21a48c8 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/arena.go @@ -0,0 +1,126 @@ +package fastjson + +import ( + "strconv" +) + +// Arena may be used for fast creation and re-use of Values. +// +// Typical Arena lifecycle: +// +// 1) Construct Values via the Arena and Value.Set* calls. +// 2) Marshal the constructed Values with Value.MarshalTo call. +// 3) Reset all the constructed Values at once by Arena.Reset call. +// 4) Go to 1 and re-use the Arena. +// +// It is unsafe calling Arena methods from concurrent goroutines. +// Use per-goroutine Arenas or ArenaPool instead. +type Arena struct { + b []byte + c cache +} + +// Reset resets all the Values allocated by a. +// +// Values previously allocated by a cannot be used after the Reset call. +func (a *Arena) Reset() { + a.b = a.b[:0] + a.c.reset() +} + +// NewObject returns new empty object value. +// +// New entries may be added to the returned object via Set call. +// +// The returned object is valid until Reset is called on a. +func (a *Arena) NewObject() *Value { + v := a.c.getValue() + v.t = TypeObject + v.o.reset() + return v +} + +// NewArray returns new empty array value. +// +// New entries may be added to the returned array via Set* calls. +// +// The returned array is valid until Reset is called on a. +func (a *Arena) NewArray() *Value { + v := a.c.getValue() + v.t = TypeArray + v.a = v.a[:0] + return v +} + +// NewString returns new string value containing s. +// +// The returned string is valid until Reset is called on a. +func (a *Arena) NewString(s string) *Value { + v := a.c.getValue() + v.t = typeRawString + bLen := len(a.b) + a.b = escapeString(a.b, s) + v.s = b2s(a.b[bLen+1 : len(a.b)-1]) + return v +} + +// NewStringBytes returns new string value containing b. +// +// The returned string is valid until Reset is called on a. +func (a *Arena) NewStringBytes(b []byte) *Value { + v := a.c.getValue() + v.t = typeRawString + bLen := len(a.b) + a.b = escapeString(a.b, b2s(b)) + v.s = b2s(a.b[bLen+1 : len(a.b)-1]) + return v +} + +// NewNumberFloat64 returns new number value containing f. +// +// The returned number is valid until Reset is called on a. +func (a *Arena) NewNumberFloat64(f float64) *Value { + v := a.c.getValue() + v.t = TypeNumber + bLen := len(a.b) + a.b = strconv.AppendFloat(a.b, f, 'g', -1, 64) + v.s = b2s(a.b[bLen:]) + return v +} + +// NewNumberInt returns new number value containing n. +// +// The returned number is valid until Reset is called on a. +func (a *Arena) NewNumberInt(n int) *Value { + v := a.c.getValue() + v.t = TypeNumber + bLen := len(a.b) + a.b = strconv.AppendInt(a.b, int64(n), 10) + v.s = b2s(a.b[bLen:]) + return v +} + +// NewNumberString returns new number value containing s. +// +// The returned number is valid until Reset is called on a. +func (a *Arena) NewNumberString(s string) *Value { + v := a.c.getValue() + v.t = TypeNumber + v.s = s + return v +} + +// NewNull returns null value. +func (a *Arena) NewNull() *Value { + return valueNull +} + +// NewTrue returns true value. +func (a *Arena) NewTrue() *Value { + return valueTrue +} + +// NewFalse return false value. +func (a *Arena) NewFalse() *Value { + return valueFalse +} diff --git a/vendor/github.com/valyala/fastjson/doc.go b/vendor/github.com/valyala/fastjson/doc.go new file mode 100644 index 0000000000..8076189cfe --- /dev/null +++ b/vendor/github.com/valyala/fastjson/doc.go @@ -0,0 +1,9 @@ +/* +Package fastjson provides fast JSON parsing. + +Arbitrary JSON may be parsed by fastjson without the need for creating structs +or for generating go code. Just parse JSON and get the required fields with +Get* functions. + +*/ +package fastjson diff --git a/vendor/github.com/valyala/fastjson/fastfloat/parse.go b/vendor/github.com/valyala/fastjson/fastfloat/parse.go new file mode 100644 index 0000000000..b37838da62 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/fastfloat/parse.go @@ -0,0 +1,515 @@ +package fastfloat + +import ( + "fmt" + "math" + "strconv" + "strings" +) + +// ParseUint64BestEffort parses uint64 number s. +// +// It is equivalent to strconv.ParseUint(s, 10, 64), but is faster. +// +// 0 is returned if the number cannot be parsed. +// See also ParseUint64, which returns parse error if the number cannot be parsed. +func ParseUint64BestEffort(s string) uint64 { + if len(s) == 0 { + return 0 + } + i := uint(0) + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + dd, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return 0 + } + return dd + } + continue + } + break + } + if i <= j { + return 0 + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0 + } + return d +} + +// ParseUint64 parses uint64 from s. +// +// It is equivalent to strconv.ParseUint(s, 10, 64), but is faster. +// +// See also ParseUint64BestEffort. +func ParseUint64(s string) (uint64, error) { + if len(s) == 0 { + return 0, fmt.Errorf("cannot parse uint64 from empty string") + } + i := uint(0) + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + dd, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return 0, err + } + return dd, nil + } + continue + } + break + } + if i <= j { + return 0, fmt.Errorf("cannot parse uint64 from %q", s) + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0, fmt.Errorf("unparsed tail left after parsing uint64 from %q: %q", s, s[i:]) + } + return d, nil +} + +// ParseInt64BestEffort parses int64 number s. +// +// It is equivalent to strconv.ParseInt(s, 10, 64), but is faster. +// +// 0 is returned if the number cannot be parsed. +// See also ParseInt64, which returns parse error if the number cannot be parsed. +func ParseInt64BestEffort(s string) int64 { + if len(s) == 0 { + return 0 + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0 + } + } + + d := int64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + int64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for int64. + // Fall back to slow parsing. + dd, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return 0 + } + return dd + } + continue + } + break + } + if i <= j { + return 0 + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0 + } + if minus { + d = -d + } + return d +} + +// ParseInt64 parses int64 number s. +// +// It is equivalent to strconv.ParseInt(s, 10, 64), but is faster. +// +// See also ParseInt64BestEffort. +func ParseInt64(s string) (int64, error) { + if len(s) == 0 { + return 0, fmt.Errorf("cannot parse int64 from empty string") + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse int64 from %q", s) + } + } + + d := int64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + int64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for int64. + // Fall back to slow parsing. + dd, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return 0, err + } + return dd, nil + } + continue + } + break + } + if i <= j { + return 0, fmt.Errorf("cannot parse int64 from %q", s) + } + if i < uint(len(s)) { + // Unparsed tail left. + return 0, fmt.Errorf("unparsed tail left after parsing int64 form %q: %q", s, s[i:]) + } + if minus { + d = -d + } + return d, nil +} + +// Exact powers of 10. +// +// This works faster than math.Pow10, since it avoids additional multiplication. +var float64pow10 = [...]float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, +} + +// ParseBestEffort parses floating-point number s. +// +// It is equivalent to strconv.ParseFloat(s, 64), but is faster. +// +// 0 is returned if the number cannot be parsed. +// See also Parse, which returns parse error if the number cannot be parsed. +func ParseBestEffort(s string) float64 { + if len(s) == 0 { + return 0 + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0 + } + } + + // the integer part might be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + if s[i] == '.' && (i+1 >= uint(len(s)) || s[i+1] < '0' || s[i+1] > '9') { + return 0 + } + + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0 + } + return f + } + continue + } + break + } + if i <= j && s[i] != '.' { + s = s[i:] + if strings.HasPrefix(s, "+") { + s = s[1:] + } + // "infinity" is needed for OpenMetrics support. + // See https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md + if strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { + if minus { + return -inf + } + return inf + } + if strings.EqualFold(s, "nan") { + return nan + } + return 0 + } + f := float64(d) + if i >= uint(len(s)) { + // Fast path - just integer. + if minus { + f = -f + } + return f + } + + if s[i] == '.' { + // Parse fractional part. + i++ + if i >= uint(len(s)) { + // the fractional part may be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + return f + } + k := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i-j >= uint(len(float64pow10)) { + // The mantissa is out of range. Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0 + } + return f + } + continue + } + break + } + if i < k { + return 0 + } + // Convert the entire mantissa to a float at once to avoid rounding errors. + f = float64(d) / float64pow10[i-k] + if i >= uint(len(s)) { + // Fast path - parsed fractional number. + if minus { + f = -f + } + return f + } + } + if s[i] == 'e' || s[i] == 'E' { + // Parse exponent part. + i++ + if i >= uint(len(s)) { + return 0 + } + expMinus := false + if s[i] == '+' || s[i] == '-' { + expMinus = s[i] == '-' + i++ + if i >= uint(len(s)) { + return 0 + } + } + exp := int16(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + exp = exp*10 + int16(s[i]-'0') + i++ + if exp > 300 { + // The exponent may be too big for float64. + // Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0 + } + return f + } + continue + } + break + } + if i <= j { + return 0 + } + if expMinus { + exp = -exp + } + f *= math.Pow10(int(exp)) + if i >= uint(len(s)) { + if minus { + f = -f + } + return f + } + } + return 0 +} + +// Parse parses floating-point number s. +// +// It is equivalent to strconv.ParseFloat(s, 64), but is faster. +// +// See also ParseBestEffort. +func Parse(s string) (float64, error) { + if len(s) == 0 { + return 0, fmt.Errorf("cannot parse float64 from empty string") + } + i := uint(0) + minus := s[0] == '-' + if minus { + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse float64 from %q", s) + } + } + + // the integer part might be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + if s[i] == '.' && (i+1 >= uint(len(s)) || s[i+1] < '0' || s[i+1] > '9') { + return 0, fmt.Errorf("missing integer and fractional part in %q", s) + } + + d := uint64(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i > 18 { + // The integer part may be out of range for uint64. + // Fall back to slow parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0, err + } + return f, nil + } + continue + } + break + } + if i <= j && s[i] != '.' { + ss := s[i:] + if strings.HasPrefix(ss, "+") { + ss = ss[1:] + } + // "infinity" is needed for OpenMetrics support. + // See https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md + if strings.EqualFold(ss, "inf") || strings.EqualFold(ss, "infinity") { + if minus { + return -inf, nil + } + return inf, nil + } + if strings.EqualFold(ss, "nan") { + return nan, nil + } + return 0, fmt.Errorf("unparsed tail left after parsing float64 from %q: %q", s, ss) + } + f := float64(d) + if i >= uint(len(s)) { + // Fast path - just integer. + if minus { + f = -f + } + return f, nil + } + + if s[i] == '.' { + // Parse fractional part. + i++ + if i >= uint(len(s)) { + // the fractional part might be elided to remain compliant + // with https://go.dev/ref/spec#Floating-point_literals + return f, nil + } + k := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + d = d*10 + uint64(s[i]-'0') + i++ + if i-j >= uint(len(float64pow10)) { + // The mantissa is out of range. Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0, fmt.Errorf("cannot parse mantissa in %q: %s", s, err) + } + return f, nil + } + continue + } + break + } + if i < k { + return 0, fmt.Errorf("cannot find mantissa in %q", s) + } + // Convert the entire mantissa to a float at once to avoid rounding errors. + f = float64(d) / float64pow10[i-k] + if i >= uint(len(s)) { + // Fast path - parsed fractional number. + if minus { + f = -f + } + return f, nil + } + } + if s[i] == 'e' || s[i] == 'E' { + // Parse exponent part. + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse exponent in %q", s) + } + expMinus := false + if s[i] == '+' || s[i] == '-' { + expMinus = s[i] == '-' + i++ + if i >= uint(len(s)) { + return 0, fmt.Errorf("cannot parse exponent in %q", s) + } + } + exp := int16(0) + j := i + for i < uint(len(s)) { + if s[i] >= '0' && s[i] <= '9' { + exp = exp*10 + int16(s[i]-'0') + i++ + if exp > 300 { + // The exponent may be too big for float64. + // Fall back to standard parsing. + f, err := strconv.ParseFloat(s, 64) + if err != nil && !math.IsInf(f, 0) { + return 0, fmt.Errorf("cannot parse exponent in %q: %s", s, err) + } + return f, nil + } + continue + } + break + } + if i <= j { + return 0, fmt.Errorf("cannot parse exponent in %q", s) + } + if expMinus { + exp = -exp + } + f *= math.Pow10(int(exp)) + if i >= uint(len(s)) { + if minus { + f = -f + } + return f, nil + } + } + return 0, fmt.Errorf("cannot parse float64 from %q", s) +} + +var inf = math.Inf(1) +var nan = math.NaN() diff --git a/vendor/github.com/valyala/fastjson/fuzz.go b/vendor/github.com/valyala/fastjson/fuzz.go new file mode 100644 index 0000000000..9130797c70 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/fuzz.go @@ -0,0 +1,22 @@ +// +build gofuzz + +package fastjson + +func Fuzz(data []byte) int { + err := ValidateBytes(data) + if err != nil { + return 0 + } + + v := MustParseBytes(data) + + dst := make([]byte, 0) + dst = v.MarshalTo(dst) + + err = ValidateBytes(dst) + if err != nil { + panic(err) + } + + return 1 +} diff --git a/vendor/github.com/valyala/fastjson/handy.go b/vendor/github.com/valyala/fastjson/handy.go new file mode 100644 index 0000000000..a5d5618f09 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/handy.go @@ -0,0 +1,170 @@ +package fastjson + +var handyPool ParserPool + +// GetString returns string value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// An empty string is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetString(data []byte, keys ...string) string { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return "" + } + sb := v.GetStringBytes(keys...) + str := string(sb) + handyPool.Put(p) + return str +} + +// GetBytes returns string value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetBytes(data []byte, keys ...string) []byte { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return nil + } + sb := v.GetStringBytes(keys...) + + // Make a copy of sb, since sb belongs to p. + var b []byte + if sb != nil { + b = append(b, sb...) + } + + handyPool.Put(p) + return b +} + +// GetInt returns int value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetInt(data []byte, keys ...string) int { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return 0 + } + n := v.GetInt(keys...) + handyPool.Put(p) + return n +} + +// GetFloat64 returns float64 value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetFloat64(data []byte, keys ...string) float64 { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return 0 + } + f := v.GetFloat64(keys...) + handyPool.Put(p) + return f +} + +// GetBool returns boolean value for the field identified by keys path +// in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// False is returned on error. Use Parser for proper error handling. +// +// Parser is faster for obtaining multiple fields from JSON. +func GetBool(data []byte, keys ...string) bool { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return false + } + b := v.GetBool(keys...) + handyPool.Put(p) + return b +} + +// Exists returns true if the field identified by keys path exists in JSON data. +// +// Array indexes may be represented as decimal numbers in keys. +// +// False is returned on error. Use Parser for proper error handling. +// +// Parser is faster when multiple fields must be checked in the JSON. +func Exists(data []byte, keys ...string) bool { + p := handyPool.Get() + v, err := p.ParseBytes(data) + if err != nil { + handyPool.Put(p) + return false + } + ok := v.Exists(keys...) + handyPool.Put(p) + return ok +} + +// Parse parses json string s. +// +// The function is slower than the Parser.Parse for re-used Parser. +func Parse(s string) (*Value, error) { + var p Parser + return p.Parse(s) +} + +// MustParse parses json string s. +// +// The function panics if s cannot be parsed. +// The function is slower than the Parser.Parse for re-used Parser. +func MustParse(s string) *Value { + v, err := Parse(s) + if err != nil { + panic(err) + } + return v +} + +// ParseBytes parses b containing json. +// +// The function is slower than the Parser.ParseBytes for re-used Parser. +func ParseBytes(b []byte) (*Value, error) { + var p Parser + return p.ParseBytes(b) +} + +// MustParseBytes parses b containing json. +// +// The function panics if b cannot be parsed. +// The function is slower than the Parser.ParseBytes for re-used Parser. +func MustParseBytes(b []byte) *Value { + v, err := ParseBytes(b) + if err != nil { + panic(err) + } + return v +} diff --git a/vendor/github.com/valyala/fastjson/parser.go b/vendor/github.com/valyala/fastjson/parser.go new file mode 100644 index 0000000000..885e1841ef --- /dev/null +++ b/vendor/github.com/valyala/fastjson/parser.go @@ -0,0 +1,976 @@ +package fastjson + +import ( + "fmt" + "github.com/valyala/fastjson/fastfloat" + "strconv" + "strings" + "unicode/utf16" +) + +// Parser parses JSON. +// +// Parser may be re-used for subsequent parsing. +// +// Parser cannot be used from concurrent goroutines. +// Use per-goroutine parsers or ParserPool instead. +type Parser struct { + // b contains working copy of the string to be parsed. + b []byte + + // c is a cache for json values. + c cache +} + +// Parse parses s containing JSON. +// +// The returned value is valid until the next call to Parse*. +// +// Use Scanner if a stream of JSON values must be parsed. +func (p *Parser) Parse(s string) (*Value, error) { + s = skipWS(s) + p.b = append(p.b[:0], s...) + p.c.reset() + + v, tail, err := parseValue(b2s(p.b), &p.c, 0) + if err != nil { + return nil, fmt.Errorf("cannot parse JSON: %s; unparsed tail: %q", err, startEndString(tail)) + } + tail = skipWS(tail) + if len(tail) > 0 { + return nil, fmt.Errorf("unexpected tail: %q", startEndString(tail)) + } + return v, nil +} + +// ParseBytes parses b containing JSON. +// +// The returned Value is valid until the next call to Parse*. +// +// Use Scanner if a stream of JSON values must be parsed. +func (p *Parser) ParseBytes(b []byte) (*Value, error) { + return p.Parse(b2s(b)) +} + +type cache struct { + vs []Value +} + +func (c *cache) reset() { + c.vs = c.vs[:0] +} + +func (c *cache) getValue() *Value { + if cap(c.vs) > len(c.vs) { + c.vs = c.vs[:len(c.vs)+1] + } else { + c.vs = append(c.vs, Value{}) + } + // Do not reset the value, since the caller must properly init it. + return &c.vs[len(c.vs)-1] +} + +func skipWS(s string) string { + if len(s) == 0 || s[0] > 0x20 { + // Fast path. + return s + } + return skipWSSlow(s) +} + +func skipWSSlow(s string) string { + if len(s) == 0 || s[0] != 0x20 && s[0] != 0x0A && s[0] != 0x09 && s[0] != 0x0D { + return s + } + for i := 1; i < len(s); i++ { + if s[i] != 0x20 && s[i] != 0x0A && s[i] != 0x09 && s[i] != 0x0D { + return s[i:] + } + } + return "" +} + +type kv struct { + k string + v *Value +} + +// MaxDepth is the maximum depth for nested JSON. +const MaxDepth = 300 + +func parseValue(s string, c *cache, depth int) (*Value, string, error) { + if len(s) == 0 { + return nil, s, fmt.Errorf("cannot parse empty string") + } + depth++ + if depth > MaxDepth { + return nil, s, fmt.Errorf("too big depth for the nested JSON; it exceeds %d", MaxDepth) + } + + if s[0] == '{' { + v, tail, err := parseObject(s[1:], c, depth) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse object: %s", err) + } + return v, tail, nil + } + if s[0] == '[' { + v, tail, err := parseArray(s[1:], c, depth) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse array: %s", err) + } + return v, tail, nil + } + if s[0] == '"' { + ss, tail, err := parseRawString(s[1:]) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse string: %s", err) + } + v := c.getValue() + v.t = typeRawString + v.s = ss + return v, tail, nil + } + if s[0] == 't' { + if len(s) < len("true") || s[:len("true")] != "true" { + return nil, s, fmt.Errorf("unexpected value found: %q", s) + } + return valueTrue, s[len("true"):], nil + } + if s[0] == 'f' { + if len(s) < len("false") || s[:len("false")] != "false" { + return nil, s, fmt.Errorf("unexpected value found: %q", s) + } + return valueFalse, s[len("false"):], nil + } + if s[0] == 'n' { + if len(s) < len("null") || s[:len("null")] != "null" { + // Try parsing NaN + if len(s) >= 3 && strings.EqualFold(s[:3], "nan") { + v := c.getValue() + v.t = TypeNumber + v.s = s[:3] + return v, s[3:], nil + } + return nil, s, fmt.Errorf("unexpected value found: %q", s) + } + return valueNull, s[len("null"):], nil + } + + ns, tail, err := parseRawNumber(s) + if err != nil { + return nil, tail, fmt.Errorf("cannot parse number: %s", err) + } + v := c.getValue() + v.t = TypeNumber + v.s = ns + return v, tail, nil +} + +func parseArray(s string, c *cache, depth int) (*Value, string, error) { + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("missing ']'") + } + + if s[0] == ']' { + v := c.getValue() + v.t = TypeArray + v.a = v.a[:0] + return v, s[1:], nil + } + + a := c.getValue() + a.t = TypeArray + a.a = a.a[:0] + for { + var v *Value + var err error + + s = skipWS(s) + v, s, err = parseValue(s, c, depth) + if err != nil { + return nil, s, fmt.Errorf("cannot parse array value: %s", err) + } + a.a = append(a.a, v) + + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("unexpected end of array") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == ']' { + s = s[1:] + return a, s, nil + } + return nil, s, fmt.Errorf("missing ',' after array value") + } +} + +func parseObject(s string, c *cache, depth int) (*Value, string, error) { + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("missing '}'") + } + + if s[0] == '}' { + v := c.getValue() + v.t = TypeObject + v.o.reset() + return v, s[1:], nil + } + + o := c.getValue() + o.t = TypeObject + o.o.reset() + for { + var err error + kv := o.o.getKV() + + // Parse key. + s = skipWS(s) + if len(s) == 0 || s[0] != '"' { + return nil, s, fmt.Errorf(`cannot find opening '"" for object key`) + } + kv.k, s, err = parseRawKey(s[1:]) + if err != nil { + return nil, s, fmt.Errorf("cannot parse object key: %s", err) + } + s = skipWS(s) + if len(s) == 0 || s[0] != ':' { + return nil, s, fmt.Errorf("missing ':' after object key") + } + s = s[1:] + + // Parse value + s = skipWS(s) + kv.v, s, err = parseValue(s, c, depth) + if err != nil { + return nil, s, fmt.Errorf("cannot parse object value: %s", err) + } + s = skipWS(s) + if len(s) == 0 { + return nil, s, fmt.Errorf("unexpected end of object") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == '}' { + return o, s[1:], nil + } + return nil, s, fmt.Errorf("missing ',' after object value") + } +} + +func escapeString(dst []byte, s string) []byte { + if !hasSpecialChars(s) { + // Fast path - nothing to escape. + dst = append(dst, '"') + dst = append(dst, s...) + dst = append(dst, '"') + return dst + } + + // Slow path. + return strconv.AppendQuote(dst, s) +} + +func hasSpecialChars(s string) bool { + if strings.IndexByte(s, '"') >= 0 || strings.IndexByte(s, '\\') >= 0 { + return true + } + for i := 0; i < len(s); i++ { + if s[i] < 0x20 { + return true + } + } + return false +} + +func unescapeStringBestEffort(s string) string { + n := strings.IndexByte(s, '\\') + if n < 0 { + // Fast path - nothing to unescape. + return s + } + + // Slow path - unescape string. + b := s2b(s) // It is safe to do, since s points to a byte slice in Parser.b. + b = b[:n] + s = s[n+1:] + for len(s) > 0 { + ch := s[0] + s = s[1:] + switch ch { + case '"': + b = append(b, '"') + case '\\': + b = append(b, '\\') + case '/': + b = append(b, '/') + case 'b': + b = append(b, '\b') + case 'f': + b = append(b, '\f') + case 'n': + b = append(b, '\n') + case 'r': + b = append(b, '\r') + case 't': + b = append(b, '\t') + case 'u': + if len(s) < 4 { + // Too short escape sequence. Just store it unchanged. + b = append(b, "\\u"...) + break + } + xs := s[:4] + x, err := strconv.ParseUint(xs, 16, 16) + if err != nil { + // Invalid escape sequence. Just store it unchanged. + b = append(b, "\\u"...) + break + } + s = s[4:] + if !utf16.IsSurrogate(rune(x)) { + b = append(b, string(rune(x))...) + break + } + + // Surrogate. + // See https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + b = append(b, "\\u"...) + b = append(b, xs...) + break + } + x1, err := strconv.ParseUint(s[2:6], 16, 16) + if err != nil { + b = append(b, "\\u"...) + b = append(b, xs...) + break + } + r := utf16.DecodeRune(rune(x), rune(x1)) + b = append(b, string(r)...) + s = s[6:] + default: + // Unknown escape sequence. Just store it unchanged. + b = append(b, '\\', ch) + } + n = strings.IndexByte(s, '\\') + if n < 0 { + b = append(b, s...) + break + } + b = append(b, s[:n]...) + s = s[n+1:] + } + return b2s(b) +} + +// parseRawKey is similar to parseRawString, but is optimized +// for small-sized keys without escape sequences. +func parseRawKey(s string) (string, string, error) { + for i := 0; i < len(s); i++ { + if s[i] == '"' { + // Fast path. + return s[:i], s[i+1:], nil + } + if s[i] == '\\' { + // Slow path. + return parseRawString(s) + } + } + return s, "", fmt.Errorf(`missing closing '"'`) +} + +func parseRawString(s string) (string, string, error) { + n := strings.IndexByte(s, '"') + if n < 0 { + return s, "", fmt.Errorf(`missing closing '"'`) + } + if n == 0 || s[n-1] != '\\' { + // Fast path. No escaped ". + return s[:n], s[n+1:], nil + } + + // Slow path - possible escaped " found. + ss := s + for { + i := n - 1 + for i > 0 && s[i-1] == '\\' { + i-- + } + if uint(n-i)%2 == 0 { + return ss[:len(ss)-len(s)+n], s[n+1:], nil + } + s = s[n+1:] + + n = strings.IndexByte(s, '"') + if n < 0 { + return ss, "", fmt.Errorf(`missing closing '"'`) + } + if n == 0 || s[n-1] != '\\' { + return ss[:len(ss)-len(s)+n], s[n+1:], nil + } + } +} + +func parseRawNumber(s string) (string, string, error) { + // The caller must ensure len(s) > 0 + + // Find the end of the number. + for i := 0; i < len(s); i++ { + ch := s[i] + if (ch >= '0' && ch <= '9') || ch == '.' || ch == '-' || ch == 'e' || ch == 'E' || ch == '+' { + continue + } + if i == 0 || i == 1 && (s[0] == '-' || s[0] == '+') { + if len(s[i:]) >= 3 { + xs := s[i : i+3] + if strings.EqualFold(xs, "inf") || strings.EqualFold(xs, "nan") { + return s[:i+3], s[i+3:], nil + } + } + return "", s, fmt.Errorf("unexpected char: %q", s[:1]) + } + ns := s[:i] + s = s[i:] + return ns, s, nil + } + return s, "", nil +} + +// Object represents JSON object. +// +// Object cannot be used from concurrent goroutines. +// Use per-goroutine parsers or ParserPool instead. +type Object struct { + kvs []kv + keysUnescaped bool +} + +func (o *Object) reset() { + o.kvs = o.kvs[:0] + o.keysUnescaped = false +} + +// MarshalTo appends marshaled o to dst and returns the result. +func (o *Object) MarshalTo(dst []byte) []byte { + dst = append(dst, '{') + for i, kv := range o.kvs { + if o.keysUnescaped { + dst = escapeString(dst, kv.k) + } else { + dst = append(dst, '"') + dst = append(dst, kv.k...) + dst = append(dst, '"') + } + dst = append(dst, ':') + dst = kv.v.MarshalTo(dst) + if i != len(o.kvs)-1 { + dst = append(dst, ',') + } + } + dst = append(dst, '}') + return dst +} + +// String returns string representation for the o. +// +// This function is for debugging purposes only. It isn't optimized for speed. +// See MarshalTo instead. +func (o *Object) String() string { + b := o.MarshalTo(nil) + // It is safe converting b to string without allocation, since b is no longer + // reachable after this line. + return b2s(b) +} + +func (o *Object) getKV() *kv { + if cap(o.kvs) > len(o.kvs) { + o.kvs = o.kvs[:len(o.kvs)+1] + } else { + o.kvs = append(o.kvs, kv{}) + } + return &o.kvs[len(o.kvs)-1] +} + +func (o *Object) unescapeKeys() { + if o.keysUnescaped { + return + } + kvs := o.kvs + for i := range kvs { + kv := &kvs[i] + kv.k = unescapeStringBestEffort(kv.k) + } + o.keysUnescaped = true +} + +// Len returns the number of items in the o. +func (o *Object) Len() int { + return len(o.kvs) +} + +// Get returns the value for the given key in the o. +// +// Returns nil if the value for the given key isn't found. +// +// The returned value is valid until Parse is called on the Parser returned o. +func (o *Object) Get(key string) *Value { + if !o.keysUnescaped && strings.IndexByte(key, '\\') < 0 { + // Fast path - try searching for the key without object keys unescaping. + for _, kv := range o.kvs { + if kv.k == key { + return kv.v + } + } + } + + // Slow path - unescape object keys. + o.unescapeKeys() + + for _, kv := range o.kvs { + if kv.k == key { + return kv.v + } + } + return nil +} + +// Visit calls f for each item in the o in the original order +// of the parsed JSON. +// +// f cannot hold key and/or v after returning. +func (o *Object) Visit(f func(key []byte, v *Value)) { + if o == nil { + return + } + + o.unescapeKeys() + + for _, kv := range o.kvs { + f(s2b(kv.k), kv.v) + } +} + +// Value represents any JSON value. +// +// Call Type in order to determine the actual type of the JSON value. +// +// Value cannot be used from concurrent goroutines. +// Use per-goroutine parsers or ParserPool instead. +type Value struct { + o Object + a []*Value + s string + t Type +} + +// MarshalTo appends marshaled v to dst and returns the result. +func (v *Value) MarshalTo(dst []byte) []byte { + switch v.t { + case typeRawString: + dst = append(dst, '"') + dst = append(dst, v.s...) + dst = append(dst, '"') + return dst + case TypeObject: + return v.o.MarshalTo(dst) + case TypeArray: + dst = append(dst, '[') + for i, vv := range v.a { + dst = vv.MarshalTo(dst) + if i != len(v.a)-1 { + dst = append(dst, ',') + } + } + dst = append(dst, ']') + return dst + case TypeString: + return escapeString(dst, v.s) + case TypeNumber: + return append(dst, v.s...) + case TypeTrue: + return append(dst, "true"...) + case TypeFalse: + return append(dst, "false"...) + case TypeNull: + return append(dst, "null"...) + default: + panic(fmt.Errorf("BUG: unexpected Value type: %d", v.t)) + } +} + +// String returns string representation of the v. +// +// The function is for debugging purposes only. It isn't optimized for speed. +// See MarshalTo instead. +// +// Don't confuse this function with StringBytes, which must be called +// for obtaining the underlying JSON string for the v. +func (v *Value) String() string { + b := v.MarshalTo(nil) + // It is safe converting b to string without allocation, since b is no longer + // reachable after this line. + return b2s(b) +} + +// Type represents JSON type. +type Type int + +const ( + // TypeNull is JSON null. + TypeNull Type = 0 + + // TypeObject is JSON object type. + TypeObject Type = 1 + + // TypeArray is JSON array type. + TypeArray Type = 2 + + // TypeString is JSON string type. + TypeString Type = 3 + + // TypeNumber is JSON number type. + TypeNumber Type = 4 + + // TypeTrue is JSON true. + TypeTrue Type = 5 + + // TypeFalse is JSON false. + TypeFalse Type = 6 + + typeRawString Type = 7 +) + +// String returns string representation of t. +func (t Type) String() string { + switch t { + case TypeObject: + return "object" + case TypeArray: + return "array" + case TypeString: + return "string" + case TypeNumber: + return "number" + case TypeTrue: + return "true" + case TypeFalse: + return "false" + case TypeNull: + return "null" + + // typeRawString is skipped intentionally, + // since it shouldn't be visible to user. + default: + panic(fmt.Errorf("BUG: unknown Value type: %d", t)) + } +} + +// Type returns the type of the v. +func (v *Value) Type() Type { + if v.t == typeRawString { + v.s = unescapeStringBestEffort(v.s) + v.t = TypeString + } + return v.t +} + +// Exists returns true if the field exists for the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +func (v *Value) Exists(keys ...string) bool { + v = v.Get(keys...) + return v != nil +} + +// Get returns value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path. +// +// The returned value is valid until Parse is called on the Parser returned v. +func (v *Value) Get(keys ...string) *Value { + if v == nil { + return nil + } + for _, key := range keys { + if v.t == TypeObject { + v = v.o.Get(key) + if v == nil { + return nil + } + } else if v.t == TypeArray { + n, err := strconv.Atoi(key) + if err != nil || n < 0 || n >= len(v.a) { + return nil + } + v = v.a[n] + } else { + return nil + } + } + return v +} + +// GetObject returns object value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path or for invalid value type. +// +// The returned object is valid until Parse is called on the Parser returned v. +func (v *Value) GetObject(keys ...string) *Object { + v = v.Get(keys...) + if v == nil || v.t != TypeObject { + return nil + } + return &v.o +} + +// GetArray returns array value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path or for invalid value type. +// +// The returned array is valid until Parse is called on the Parser returned v. +func (v *Value) GetArray(keys ...string) []*Value { + v = v.Get(keys...) + if v == nil || v.t != TypeArray { + return nil + } + return v.a +} + +// GetFloat64 returns float64 value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetFloat64(keys ...string) float64 { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + return fastfloat.ParseBestEffort(v.s) +} + +// GetInt returns int value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetInt(keys ...string) int { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + n := fastfloat.ParseInt64BestEffort(v.s) + nn := int(n) + if int64(nn) != n { + return 0 + } + return nn +} + +// GetUint returns uint value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetUint(keys ...string) uint { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + n := fastfloat.ParseUint64BestEffort(v.s) + nn := uint(n) + if uint64(nn) != n { + return 0 + } + return nn +} + +// GetInt64 returns int64 value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetInt64(keys ...string) int64 { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + return fastfloat.ParseInt64BestEffort(v.s) +} + +// GetUint64 returns uint64 value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// 0 is returned for non-existing keys path or for invalid value type. +func (v *Value) GetUint64(keys ...string) uint64 { + v = v.Get(keys...) + if v == nil || v.Type() != TypeNumber { + return 0 + } + return fastfloat.ParseUint64BestEffort(v.s) +} + +// GetStringBytes returns string value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// nil is returned for non-existing keys path or for invalid value type. +// +// The returned string is valid until Parse is called on the Parser returned v. +func (v *Value) GetStringBytes(keys ...string) []byte { + v = v.Get(keys...) + if v == nil || v.Type() != TypeString { + return nil + } + return s2b(v.s) +} + +// GetBool returns bool value by the given keys path. +// +// Array indexes may be represented as decimal numbers in keys. +// +// false is returned for non-existing keys path or for invalid value type. +func (v *Value) GetBool(keys ...string) bool { + v = v.Get(keys...) + if v != nil && v.t == TypeTrue { + return true + } + return false +} + +// Object returns the underlying JSON object for the v. +// +// The returned object is valid until Parse is called on the Parser returned v. +// +// Use GetObject if you don't need error handling. +func (v *Value) Object() (*Object, error) { + if v.t != TypeObject { + return nil, fmt.Errorf("value doesn't contain object; it contains %s", v.Type()) + } + return &v.o, nil +} + +// Array returns the underlying JSON array for the v. +// +// The returned array is valid until Parse is called on the Parser returned v. +// +// Use GetArray if you don't need error handling. +func (v *Value) Array() ([]*Value, error) { + if v.t != TypeArray { + return nil, fmt.Errorf("value doesn't contain array; it contains %s", v.Type()) + } + return v.a, nil +} + +// StringBytes returns the underlying JSON string for the v. +// +// The returned string is valid until Parse is called on the Parser returned v. +// +// Use GetStringBytes if you don't need error handling. +func (v *Value) StringBytes() ([]byte, error) { + if v.Type() != TypeString { + return nil, fmt.Errorf("value doesn't contain string; it contains %s", v.Type()) + } + return s2b(v.s), nil +} + +// Float64 returns the underlying JSON number for the v. +// +// Use GetFloat64 if you don't need error handling. +func (v *Value) Float64() (float64, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + return fastfloat.Parse(v.s) +} + +// Int returns the underlying JSON int for the v. +// +// Use GetInt if you don't need error handling. +func (v *Value) Int() (int, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + n, err := fastfloat.ParseInt64(v.s) + if err != nil { + return 0, err + } + nn := int(n) + if int64(nn) != n { + return 0, fmt.Errorf("number %q doesn't fit int", v.s) + } + return nn, nil +} + +// Uint returns the underlying JSON uint for the v. +// +// Use GetInt if you don't need error handling. +func (v *Value) Uint() (uint, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + n, err := fastfloat.ParseUint64(v.s) + if err != nil { + return 0, err + } + nn := uint(n) + if uint64(nn) != n { + return 0, fmt.Errorf("number %q doesn't fit uint", v.s) + } + return nn, nil +} + +// Int64 returns the underlying JSON int64 for the v. +// +// Use GetInt64 if you don't need error handling. +func (v *Value) Int64() (int64, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + return fastfloat.ParseInt64(v.s) +} + +// Uint64 returns the underlying JSON uint64 for the v. +// +// Use GetInt64 if you don't need error handling. +func (v *Value) Uint64() (uint64, error) { + if v.Type() != TypeNumber { + return 0, fmt.Errorf("value doesn't contain number; it contains %s", v.Type()) + } + return fastfloat.ParseUint64(v.s) +} + +// Bool returns the underlying JSON bool for the v. +// +// Use GetBool if you don't need error handling. +func (v *Value) Bool() (bool, error) { + if v.t == TypeTrue { + return true, nil + } + if v.t == TypeFalse { + return false, nil + } + return false, fmt.Errorf("value doesn't contain bool; it contains %s", v.Type()) +} + +var ( + valueTrue = &Value{t: TypeTrue} + valueFalse = &Value{t: TypeFalse} + valueNull = &Value{t: TypeNull} +) diff --git a/vendor/github.com/valyala/fastjson/pool.go b/vendor/github.com/valyala/fastjson/pool.go new file mode 100644 index 0000000000..00cfb42fa6 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/pool.go @@ -0,0 +1,52 @@ +package fastjson + +import ( + "sync" +) + +// ParserPool may be used for pooling Parsers for similarly typed JSONs. +type ParserPool struct { + pool sync.Pool +} + +// Get returns a Parser from pp. +// +// The Parser must be Put to pp after use. +func (pp *ParserPool) Get() *Parser { + v := pp.pool.Get() + if v == nil { + return &Parser{} + } + return v.(*Parser) +} + +// Put returns p to pp. +// +// p and objects recursively returned from p cannot be used after p +// is put into pp. +func (pp *ParserPool) Put(p *Parser) { + pp.pool.Put(p) +} + +// ArenaPool may be used for pooling Arenas for similarly typed JSONs. +type ArenaPool struct { + pool sync.Pool +} + +// Get returns an Arena from ap. +// +// The Arena must be Put to ap after use. +func (ap *ArenaPool) Get() *Arena { + v := ap.pool.Get() + if v == nil { + return &Arena{} + } + return v.(*Arena) +} + +// Put returns a to ap. +// +// a and objects created by a cannot be used after a is put into ap. +func (ap *ArenaPool) Put(a *Arena) { + ap.pool.Put(a) +} diff --git a/vendor/github.com/valyala/fastjson/scanner.go b/vendor/github.com/valyala/fastjson/scanner.go new file mode 100644 index 0000000000..89b38816f0 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/scanner.go @@ -0,0 +1,94 @@ +package fastjson + +import ( + "errors" +) + +// Scanner scans a series of JSON values. Values may be delimited by whitespace. +// +// Scanner may parse JSON lines ( http://jsonlines.org/ ). +// +// Scanner may be re-used for subsequent parsing. +// +// Scanner cannot be used from concurrent goroutines. +// +// Use Parser for parsing only a single JSON value. +type Scanner struct { + // b contains a working copy of json value passed to Init. + b []byte + + // s points to the next JSON value to parse. + s string + + // err contains the last error. + err error + + // v contains the last parsed JSON value. + v *Value + + // c is used for caching JSON values. + c cache +} + +// Init initializes sc with the given s. +// +// s may contain multiple JSON values, which may be delimited by whitespace. +func (sc *Scanner) Init(s string) { + sc.b = append(sc.b[:0], s...) + sc.s = b2s(sc.b) + sc.err = nil + sc.v = nil +} + +// InitBytes initializes sc with the given b. +// +// b may contain multiple JSON values, which may be delimited by whitespace. +func (sc *Scanner) InitBytes(b []byte) { + sc.Init(b2s(b)) +} + +// Next parses the next JSON value from s passed to Init. +// +// Returns true on success. The parsed value is available via Value call. +// +// Returns false either on error or on the end of s. +// Call Error in order to determine the cause of the returned false. +func (sc *Scanner) Next() bool { + if sc.err != nil { + return false + } + + sc.s = skipWS(sc.s) + if len(sc.s) == 0 { + sc.err = errEOF + return false + } + + sc.c.reset() + v, tail, err := parseValue(sc.s, &sc.c, 0) + if err != nil { + sc.err = err + return false + } + + sc.s = tail + sc.v = v + return true +} + +// Error returns the last error. +func (sc *Scanner) Error() error { + if sc.err == errEOF { + return nil + } + return sc.err +} + +// Value returns the last parsed value. +// +// The value is valid until the Next call. +func (sc *Scanner) Value() *Value { + return sc.v +} + +var errEOF = errors.New("end of s") diff --git a/vendor/github.com/valyala/fastjson/update.go b/vendor/github.com/valyala/fastjson/update.go new file mode 100644 index 0000000000..f8099bdbb9 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/update.go @@ -0,0 +1,110 @@ +package fastjson + +import ( + "strconv" + "strings" +) + +// Del deletes the entry with the given key from o. +func (o *Object) Del(key string) { + if o == nil { + return + } + if !o.keysUnescaped && strings.IndexByte(key, '\\') < 0 { + // Fast path - try searching for the key without object keys unescaping. + for i, kv := range o.kvs { + if kv.k == key { + o.kvs = append(o.kvs[:i], o.kvs[i+1:]...) + return + } + } + } + + // Slow path - unescape object keys before item search. + o.unescapeKeys() + + for i, kv := range o.kvs { + if kv.k == key { + o.kvs = append(o.kvs[:i], o.kvs[i+1:]...) + return + } + } +} + +// Del deletes the entry with the given key from array or object v. +func (v *Value) Del(key string) { + if v == nil { + return + } + if v.t == TypeObject { + v.o.Del(key) + return + } + if v.t == TypeArray { + n, err := strconv.Atoi(key) + if err != nil || n < 0 || n >= len(v.a) { + return + } + v.a = append(v.a[:n], v.a[n+1:]...) + } +} + +// Set sets (key, value) entry in the o. +// +// The value must be unchanged during o lifetime. +func (o *Object) Set(key string, value *Value) { + if o == nil { + return + } + if value == nil { + value = valueNull + } + o.unescapeKeys() + + // Try substituting already existing entry with the given key. + for i := range o.kvs { + kv := &o.kvs[i] + if kv.k == key { + kv.v = value + return + } + } + + // Add new entry. + kv := o.getKV() + kv.k = key + kv.v = value +} + +// Set sets (key, value) entry in the array or object v. +// +// The value must be unchanged during v lifetime. +func (v *Value) Set(key string, value *Value) { + if v == nil { + return + } + if v.t == TypeObject { + v.o.Set(key, value) + return + } + if v.t == TypeArray { + idx, err := strconv.Atoi(key) + if err != nil || idx < 0 { + return + } + v.SetArrayItem(idx, value) + } +} + +// SetArrayItem sets the value in the array v at idx position. +// +// The value must be unchanged during v lifetime. +func (v *Value) SetArrayItem(idx int, value *Value) { + if v == nil || v.t != TypeArray { + return + } + for idx >= len(v.a) { + v.a = append(v.a, valueNull) + } + v.a[idx] = value +} diff --git a/vendor/github.com/valyala/fastjson/util.go b/vendor/github.com/valyala/fastjson/util.go new file mode 100644 index 0000000000..03a53965a2 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/util.go @@ -0,0 +1,30 @@ +package fastjson + +import ( + "reflect" + "unsafe" +) + +func b2s(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func s2b(s string) (b []byte) { + strh := (*reflect.StringHeader)(unsafe.Pointer(&s)) + sh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + sh.Data = strh.Data + sh.Len = strh.Len + sh.Cap = strh.Len + return b +} + +const maxStartEndStringLen = 80 + +func startEndString(s string) string { + if len(s) <= maxStartEndStringLen { + return s + } + start := s[:40] + end := s[len(s)-40:] + return start + "..." + end +} diff --git a/vendor/github.com/valyala/fastjson/validate.go b/vendor/github.com/valyala/fastjson/validate.go new file mode 100644 index 0000000000..196f1c3dc6 --- /dev/null +++ b/vendor/github.com/valyala/fastjson/validate.go @@ -0,0 +1,308 @@ +package fastjson + +import ( + "fmt" + "strconv" + "strings" +) + +// Validate validates JSON s. +func Validate(s string) error { + s = skipWS(s) + + tail, err := validateValue(s) + if err != nil { + return fmt.Errorf("cannot parse JSON: %s; unparsed tail: %q", err, startEndString(tail)) + } + tail = skipWS(tail) + if len(tail) > 0 { + return fmt.Errorf("unexpected tail: %q", startEndString(tail)) + } + return nil +} + +// ValidateBytes validates JSON b. +func ValidateBytes(b []byte) error { + return Validate(b2s(b)) +} + +func validateValue(s string) (string, error) { + if len(s) == 0 { + return s, fmt.Errorf("cannot parse empty string") + } + + if s[0] == '{' { + tail, err := validateObject(s[1:]) + if err != nil { + return tail, fmt.Errorf("cannot parse object: %s", err) + } + return tail, nil + } + if s[0] == '[' { + tail, err := validateArray(s[1:]) + if err != nil { + return tail, fmt.Errorf("cannot parse array: %s", err) + } + return tail, nil + } + if s[0] == '"' { + sv, tail, err := validateString(s[1:]) + if err != nil { + return tail, fmt.Errorf("cannot parse string: %s", err) + } + // Scan the string for control chars. + for i := 0; i < len(sv); i++ { + if sv[i] < 0x20 { + return tail, fmt.Errorf("string cannot contain control char 0x%02X", sv[i]) + } + } + return tail, nil + } + if s[0] == 't' { + if len(s) < len("true") || s[:len("true")] != "true" { + return s, fmt.Errorf("unexpected value found: %q", s) + } + return s[len("true"):], nil + } + if s[0] == 'f' { + if len(s) < len("false") || s[:len("false")] != "false" { + return s, fmt.Errorf("unexpected value found: %q", s) + } + return s[len("false"):], nil + } + if s[0] == 'n' { + if len(s) < len("null") || s[:len("null")] != "null" { + return s, fmt.Errorf("unexpected value found: %q", s) + } + return s[len("null"):], nil + } + + tail, err := validateNumber(s) + if err != nil { + return tail, fmt.Errorf("cannot parse number: %s", err) + } + return tail, nil +} + +func validateArray(s string) (string, error) { + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("missing ']'") + } + if s[0] == ']' { + return s[1:], nil + } + + for { + var err error + + s = skipWS(s) + s, err = validateValue(s) + if err != nil { + return s, fmt.Errorf("cannot parse array value: %s", err) + } + + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("unexpected end of array") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == ']' { + s = s[1:] + return s, nil + } + return s, fmt.Errorf("missing ',' after array value") + } +} + +func validateObject(s string) (string, error) { + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("missing '}'") + } + if s[0] == '}' { + return s[1:], nil + } + + for { + var err error + + // Parse key. + s = skipWS(s) + if len(s) == 0 || s[0] != '"' { + return s, fmt.Errorf(`cannot find opening '"" for object key`) + } + + var key string + key, s, err = validateKey(s[1:]) + if err != nil { + return s, fmt.Errorf("cannot parse object key: %s", err) + } + // Scan the key for control chars. + for i := 0; i < len(key); i++ { + if key[i] < 0x20 { + return s, fmt.Errorf("object key cannot contain control char 0x%02X", key[i]) + } + } + s = skipWS(s) + if len(s) == 0 || s[0] != ':' { + return s, fmt.Errorf("missing ':' after object key") + } + s = s[1:] + + // Parse value + s = skipWS(s) + s, err = validateValue(s) + if err != nil { + return s, fmt.Errorf("cannot parse object value: %s", err) + } + s = skipWS(s) + if len(s) == 0 { + return s, fmt.Errorf("unexpected end of object") + } + if s[0] == ',' { + s = s[1:] + continue + } + if s[0] == '}' { + return s[1:], nil + } + return s, fmt.Errorf("missing ',' after object value") + } +} + +// validateKey is similar to validateString, but is optimized +// for typical object keys, which are quite small and have no escape sequences. +func validateKey(s string) (string, string, error) { + for i := 0; i < len(s); i++ { + if s[i] == '"' { + // Fast path - the key doesn't contain escape sequences. + return s[:i], s[i+1:], nil + } + if s[i] == '\\' { + // Slow path - the key contains escape sequences. + return validateString(s) + } + } + return "", s, fmt.Errorf(`missing closing '"'`) +} + +func validateString(s string) (string, string, error) { + // Try fast path - a string without escape sequences. + if n := strings.IndexByte(s, '"'); n >= 0 && strings.IndexByte(s[:n], '\\') < 0 { + return s[:n], s[n+1:], nil + } + + // Slow path - escape sequences are present. + rs, tail, err := parseRawString(s) + if err != nil { + return rs, tail, err + } + for { + n := strings.IndexByte(rs, '\\') + if n < 0 { + return rs, tail, nil + } + n++ + if n >= len(rs) { + return rs, tail, fmt.Errorf("BUG: parseRawString returned invalid string with trailing backslash: %q", rs) + } + ch := rs[n] + rs = rs[n+1:] + switch ch { + case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': + // Valid escape sequences - see http://json.org/ + break + case 'u': + if len(rs) < 4 { + return rs, tail, fmt.Errorf(`too short escape sequence: \u%s`, rs) + } + xs := rs[:4] + _, err := strconv.ParseUint(xs, 16, 16) + if err != nil { + return rs, tail, fmt.Errorf(`invalid escape sequence \u%s: %s`, xs, err) + } + rs = rs[4:] + default: + return rs, tail, fmt.Errorf(`unknown escape sequence \%c`, ch) + } + } +} + +func validateNumber(s string) (string, error) { + if len(s) == 0 { + return s, fmt.Errorf("zero-length number") + } + if s[0] == '-' { + s = s[1:] + if len(s) == 0 { + return s, fmt.Errorf("missing number after minus") + } + } + i := 0 + for i < len(s) { + if s[i] < '0' || s[i] > '9' { + break + } + i++ + } + if i <= 0 { + return s, fmt.Errorf("expecting 0..9 digit, got %c", s[0]) + } + if s[0] == '0' && i != 1 { + return s, fmt.Errorf("unexpected number starting from 0") + } + if i >= len(s) { + return "", nil + } + if s[i] == '.' { + // Validate fractional part + s = s[i+1:] + if len(s) == 0 { + return s, fmt.Errorf("missing fractional part") + } + i = 0 + for i < len(s) { + if s[i] < '0' || s[i] > '9' { + break + } + i++ + } + if i == 0 { + return s, fmt.Errorf("expecting 0..9 digit in fractional part, got %c", s[0]) + } + if i >= len(s) { + return "", nil + } + } + if s[i] == 'e' || s[i] == 'E' { + // Validate exponent part + s = s[i+1:] + if len(s) == 0 { + return s, fmt.Errorf("missing exponent part") + } + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) == 0 { + return s, fmt.Errorf("missing exponent part") + } + } + i = 0 + for i < len(s) { + if s[i] < '0' || s[i] > '9' { + break + } + i++ + } + if i == 0 { + return s, fmt.Errorf("expecting 0..9 digit in exponent part, got %c", s[0]) + } + if i >= len(s) { + return "", nil + } + } + return s[i:], nil +} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/core/core.go b/vendor/github.com/vektah/gqlparser/v2/validator/core/core.go new file mode 100644 index 0000000000..7a6295c2f9 --- /dev/null +++ b/vendor/github.com/vektah/gqlparser/v2/validator/core/core.go @@ -0,0 +1,24 @@ +package core + +import ( + "github.com/vektah/gqlparser/v2/gqlerror" +) + +type AddErrFunc func(options ...ErrorOption) + +type RuleFunc func(observers *Events, addError AddErrFunc) + +type Rule struct { + Name string + RuleFunc RuleFunc +} + +// NameSorter sorts Rules by name. +// usage: sort.Sort(core.NameSorter(specifiedRules)) +type NameSorter []Rule + +func (a NameSorter) Len() int { return len(a) } +func (a NameSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a NameSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } + +type ErrorOption func(err *gqlerror.Error) diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/core/helpers.go b/vendor/github.com/vektah/gqlparser/v2/validator/core/helpers.go new file mode 100644 index 0000000000..b395a8402b --- /dev/null +++ b/vendor/github.com/vektah/gqlparser/v2/validator/core/helpers.go @@ -0,0 +1,154 @@ +package core + +import ( + "bytes" + "fmt" + "math" + "sort" + "strings" + + "github.com/agnivade/levenshtein" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +func Message(msg string, args ...interface{}) ErrorOption { + return func(err *gqlerror.Error) { + err.Message += fmt.Sprintf(msg, args...) + } +} + +func At(position *ast.Position) ErrorOption { + return func(err *gqlerror.Error) { + if position == nil { + return + } + err.Locations = append(err.Locations, gqlerror.Location{ + Line: position.Line, + Column: position.Column, + }) + if position.Src.Name != "" { + err.SetFile(position.Src.Name) + } + } +} + +func SuggestListQuoted(prefix string, typed string, suggestions []string) ErrorOption { + suggested := SuggestionList(typed, suggestions) + return func(err *gqlerror.Error) { + if len(suggested) > 0 { + err.Message += " " + prefix + " " + QuotedOrList(suggested...) + "?" + } + } +} + +func SuggestListUnquoted(prefix string, typed string, suggestions []string) ErrorOption { + suggested := SuggestionList(typed, suggestions) + return func(err *gqlerror.Error) { + if len(suggested) > 0 { + err.Message += " " + prefix + " " + OrList(suggested...) + "?" + } + } +} + +func Suggestf(suggestion string, args ...interface{}) ErrorOption { + return func(err *gqlerror.Error) { + err.Message += " Did you mean " + fmt.Sprintf(suggestion, args...) + "?" + } +} + +// Given [ A, B, C ] return '"A", "B", or "C"'. +func QuotedOrList(items ...string) string { + itemsQuoted := make([]string, len(items)) + for i, item := range items { + itemsQuoted[i] = `"` + item + `"` + } + return OrList(itemsQuoted...) +} + +// Given [ A, B, C ] return 'A, B, or C'. +func OrList(items ...string) string { + var buf bytes.Buffer + + if len(items) > 5 { + items = items[:5] + } + if len(items) == 2 { + buf.WriteString(items[0]) + buf.WriteString(" or ") + buf.WriteString(items[1]) + return buf.String() + } + + for i, item := range items { + if i != 0 { + if i == len(items)-1 { + buf.WriteString(", or ") + } else { + buf.WriteString(", ") + } + } + buf.WriteString(item) + } + return buf.String() +} + +// Given an invalid input string and a list of valid options, returns a filtered +// list of valid options sorted based on their similarity with the input. +func SuggestionList(input string, options []string) []string { + var results []string + optionsByDistance := map[string]int{} + + for _, option := range options { + distance := lexicalDistance(input, option) + threshold := calcThreshold(input) + if distance <= threshold { + results = append(results, option) + optionsByDistance[option] = distance + } + } + + sort.Slice(results, func(i, j int) bool { + return optionsByDistance[results[i]] < optionsByDistance[results[j]] + }) + return results +} + +func calcThreshold(a string) (threshold int) { + // the logic is copied from here + // https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/jsutils/suggestionList.ts#L14 + threshold = int(math.Floor(float64(len(a))*0.4) + 1) + + if threshold < 1 { + threshold = 1 + } + return +} + +// Computes the lexical distance between strings A and B. +// +// The "distance" between two strings is given by counting the minimum number +// of edits needed to transform string A into string B. An edit can be an +// insertion, deletion, or substitution of a single character, or a swap of two +// adjacent characters. +// +// Includes a custom alteration from Damerau-Levenshtein to treat case changes +// as a single edit which helps identify mis-cased values with an edit distance +// of 1. +// +// This distance can be useful for detecting typos in input or sorting +func lexicalDistance(a, b string) int { + if a == b { + return 0 + } + + a = strings.ToLower(a) + b = strings.ToLower(b) + + // Any case change counts as a single edit + if a == b { + return 1 + } + + return levenshtein.ComputeDistance(a, b) +} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/walk.go b/vendor/github.com/vektah/gqlparser/v2/validator/core/walk.go similarity index 99% rename from vendor/github.com/vektah/gqlparser/v2/validator/walk.go rename to vendor/github.com/vektah/gqlparser/v2/validator/core/walk.go index d3140746fb..09a3016fd4 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/walk.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/core/walk.go @@ -1,4 +1,4 @@ -package validator +package core import ( "context" diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/error.go b/vendor/github.com/vektah/gqlparser/v2/validator/error.go deleted file mode 100644 index f8f76055ac..0000000000 --- a/vendor/github.com/vektah/gqlparser/v2/validator/error.go +++ /dev/null @@ -1,55 +0,0 @@ -package validator - -import ( - "fmt" - - "github.com/vektah/gqlparser/v2/ast" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -type ErrorOption func(err *gqlerror.Error) - -func Message(msg string, args ...interface{}) ErrorOption { - return func(err *gqlerror.Error) { - err.Message += fmt.Sprintf(msg, args...) - } -} - -func At(position *ast.Position) ErrorOption { - return func(err *gqlerror.Error) { - if position == nil { - return - } - err.Locations = append(err.Locations, gqlerror.Location{ - Line: position.Line, - Column: position.Column, - }) - if position.Src.Name != "" { - err.SetFile(position.Src.Name) - } - } -} - -func SuggestListQuoted(prefix string, typed string, suggestions []string) ErrorOption { - suggested := SuggestionList(typed, suggestions) - return func(err *gqlerror.Error) { - if len(suggested) > 0 { - err.Message += " " + prefix + " " + QuotedOrList(suggested...) + "?" - } - } -} - -func SuggestListUnquoted(prefix string, typed string, suggestions []string) ErrorOption { - suggested := SuggestionList(typed, suggestions) - return func(err *gqlerror.Error) { - if len(suggested) > 0 { - err.Message += " " + prefix + " " + OrList(suggested...) + "?" - } - } -} - -func Suggestf(suggestion string, args ...interface{}) ErrorOption { - return func(err *gqlerror.Error) { - err.Message += " Did you mean " + fmt.Sprintf(suggestion, args...) + "?" - } -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/messaging.go b/vendor/github.com/vektah/gqlparser/v2/validator/messaging.go deleted file mode 100644 index f1ab5873f3..0000000000 --- a/vendor/github.com/vektah/gqlparser/v2/validator/messaging.go +++ /dev/null @@ -1,39 +0,0 @@ -package validator - -import "bytes" - -// Given [ A, B, C ] return '"A", "B", or "C"'. -func QuotedOrList(items ...string) string { - itemsQuoted := make([]string, len(items)) - for i, item := range items { - itemsQuoted[i] = `"` + item + `"` - } - return OrList(itemsQuoted...) -} - -// Given [ A, B, C ] return 'A, B, or C'. -func OrList(items ...string) string { - var buf bytes.Buffer - - if len(items) > 5 { - items = items[:5] - } - if len(items) == 2 { - buf.WriteString(items[0]) - buf.WriteString(" or ") - buf.WriteString(items[1]) - return buf.String() - } - - for i, item := range items { - if i != 0 { - if i == len(items)-1 { - buf.WriteString(", or ") - } else { - buf.WriteString(", ") - } - } - buf.WriteString(item) - } - return buf.String() -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go index b57d2a9014..e4a67eb0cd 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go @@ -8,7 +8,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) func ruleFuncFieldsOnCorrectType(observers *Events, addError AddErrFunc, disableSuggestion bool) { @@ -48,10 +48,6 @@ var FieldsOnCorrectTypeRuleWithoutSuggestions = Rule{ }, } -func init() { - AddRule(FieldsOnCorrectTypeRule.Name, FieldsOnCorrectTypeRule.RuleFunc) -} - // Go through all the implementations of type, as well as the interfaces // that they implement. If any of those types include the provided field, // suggest them, sorted by how often the type is referenced, starting diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go index a88e3f1cf7..8fb2692589 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go @@ -6,7 +6,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var FragmentsOnCompositeTypesRule = Rule{ @@ -40,7 +40,3 @@ var FragmentsOnCompositeTypesRule = Rule{ }) }, } - -func init() { - AddRule(FragmentsOnCompositeTypesRule.Name, FragmentsOnCompositeTypesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go index 83b4e05758..4c065a715e 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) func ruleFuncKnownArgumentNames(observers *Events, addError AddErrFunc, disableSuggestion bool) { @@ -82,7 +82,3 @@ var KnownArgumentNamesRuleWithoutSuggestions = Rule{ ruleFuncKnownArgumentNames(observers, addError, true) }, } - -func init() { - AddRule(KnownArgumentNamesRule.Name, KnownArgumentNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go index ccb5efeb95..2430d29b23 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var KnownDirectivesRule = Rule{ @@ -48,7 +48,3 @@ var KnownDirectivesRule = Rule{ }) }, } - -func init() { - AddRule(KnownDirectivesRule.Name, KnownDirectivesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go index 525698fb94..c9b9f90d4a 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var KnownFragmentNamesRule = Rule{ @@ -20,7 +20,3 @@ var KnownFragmentNamesRule = Rule{ }) }, } - -func init() { - AddRule(KnownFragmentNamesRule.Name, KnownFragmentNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_root_type.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_root_type.go index aa66d16c28..b67da68ce7 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_root_type.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_root_type.go @@ -6,7 +6,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var KnownRootTypeRule = Rule{ @@ -36,7 +36,3 @@ var KnownRootTypeRule = Rule{ }) }, } - -func init() { - AddRule(KnownRootTypeRule.Name, KnownRootTypeRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go index ef85c58e65..a0f10fba75 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) func ruleFuncKnownTypeNames(observers *Events, addError AddErrFunc, disableSuggestion bool) { @@ -78,7 +78,3 @@ var KnownTypeNamesRuleWithoutSuggestions = Rule{ ruleFuncKnownTypeNames(observers, addError, true) }, } - -func init() { - AddRule(KnownTypeNamesRule.Name, KnownTypeNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go index 6e246f715f..dfa851c577 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var LoneAnonymousOperationRule = Rule{ @@ -20,7 +20,3 @@ var LoneAnonymousOperationRule = Rule{ }) }, } - -func init() { - AddRule(LoneAnonymousOperationRule.Name, LoneAnonymousOperationRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/max_introspection_depth.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/max_introspection_depth.go index 57a68b32b9..651b23b4e3 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/max_introspection_depth.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/max_introspection_depth.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) const maxListsDepth = 3 @@ -84,7 +84,3 @@ func checkDepthFragmentSpread(fragmentSpread *ast.FragmentSpread, visitedFragmen defer delete(visitedFragments, fragmentName) return checkDepthSelectionSet(fragment.SelectionSet, visitedFragments, depth) } - -func init() { - AddRule(MaxIntrospectionDepth.Name, MaxIntrospectionDepth.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go index 4e7907e243..fb3ac6ad3c 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go @@ -7,7 +7,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var NoFragmentCyclesRule = Rule{ @@ -71,10 +71,6 @@ var NoFragmentCyclesRule = Rule{ }, } -func init() { - AddRule(NoFragmentCyclesRule.Name, NoFragmentCyclesRule.RuleFunc) -} - func getFragmentSpreads(node ast.SelectionSet) []*ast.FragmentSpread { var spreads []*ast.FragmentSpread diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go index 64f2dc7764..562d7f19ce 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var NoUndefinedVariablesRule = Rule{ @@ -29,7 +29,3 @@ var NoUndefinedVariablesRule = Rule{ }) }, } - -func init() { - AddRule(NoUndefinedVariablesRule.Name, NoUndefinedVariablesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go index a914ee6d34..6d27e11e9e 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var NoUnusedFragmentsRule = Rule{ @@ -30,7 +30,3 @@ var NoUnusedFragmentsRule = Rule{ }) }, } - -func init() { - AddRule(NoUnusedFragmentsRule.Name, NoUnusedFragmentsRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go index daed80ebbb..a4ce07090c 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var NoUnusedVariablesRule = Rule{ @@ -31,7 +31,3 @@ var NoUnusedVariablesRule = Rule{ }) }, } - -func init() { - AddRule(NoUnusedVariablesRule.Name, NoUnusedVariablesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go index 1295682200..9e843e760b 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go @@ -8,7 +8,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var OverlappingFieldsCanBeMergedRule = Rule{ @@ -108,10 +108,6 @@ var OverlappingFieldsCanBeMergedRule = Rule{ }, } -func init() { - AddRule(OverlappingFieldsCanBeMergedRule.Name, OverlappingFieldsCanBeMergedRule.RuleFunc) -} - type pairSet struct { data map[string]map[string]bool } diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go index b81f375658..f932ac8c2e 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var PossibleFragmentSpreadsRule = Rule{ @@ -68,7 +68,3 @@ var PossibleFragmentSpreadsRule = Rule{ }) }, } - -func init() { - AddRule(PossibleFragmentSpreadsRule.Name, PossibleFragmentSpreadsRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go index 90667af23b..fc1a6a476d 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go @@ -3,7 +3,7 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var ProvidedRequiredArgumentsRule = Rule{ @@ -62,7 +62,3 @@ var ProvidedRequiredArgumentsRule = Rule{ }) }, } - -func init() { - AddRule(ProvidedRequiredArgumentsRule.Name, ProvidedRequiredArgumentsRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/rules.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/rules.go new file mode 100644 index 0000000000..803543ed17 --- /dev/null +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/rules.go @@ -0,0 +1,119 @@ +package rules + +import ( + "slices" + + "github.com/vektah/gqlparser/v2/validator/core" +) + +// Rules manages GraphQL validation rules. +type Rules struct { + rules map[string]core.RuleFunc + ruleNameKeys []string // for deterministic order +} + +// NewRules creates a Rules instance with the specified rules. +func NewRules(rs ...core.Rule) *Rules { + r := &Rules{ + rules: make(map[string]core.RuleFunc), + } + + for _, rule := range rs { + r.AddRule(rule.Name, rule.RuleFunc) + } + + return r +} + +// NewDefaultRules creates a Rules instance containing the default GraphQL validation rule set. +func NewDefaultRules() *Rules { + rules := []core.Rule{ + FieldsOnCorrectTypeRule, + FragmentsOnCompositeTypesRule, + KnownArgumentNamesRule, + KnownDirectivesRule, + KnownFragmentNamesRule, + KnownRootTypeRule, + KnownTypeNamesRule, + LoneAnonymousOperationRule, + MaxIntrospectionDepth, + NoFragmentCyclesRule, + NoUndefinedVariablesRule, + NoUnusedFragmentsRule, + NoUnusedVariablesRule, + OverlappingFieldsCanBeMergedRule, + PossibleFragmentSpreadsRule, + ProvidedRequiredArgumentsRule, + ScalarLeafsRule, + SingleFieldSubscriptionsRule, + UniqueArgumentNamesRule, + UniqueDirectivesPerLocationRule, + UniqueFragmentNamesRule, + UniqueInputFieldNamesRule, + UniqueOperationNamesRule, + UniqueVariableNamesRule, + ValuesOfCorrectTypeRule, + VariablesAreInputTypesRule, + VariablesInAllowedPositionRule, + } + + r := NewRules(rules...) + + return r +} + +// AddRule adds a rule with the specified name and rule function to the rule set. +// If a rule with the same name already exists, it will not be added. +func (r *Rules) AddRule(name string, ruleFunc core.RuleFunc) { + if r.rules == nil { + r.rules = make(map[string]core.RuleFunc) + } + + if _, exists := r.rules[name]; !exists { + r.rules[name] = ruleFunc + r.ruleNameKeys = append(r.ruleNameKeys, name) + } +} + +// GetInner returns the internal rule map. +// If the map is not initialized, it returns an empty map. +func (r *Rules) GetInner() map[string]core.RuleFunc { + if r == nil { + return nil // impossible nonsense, hopefully + } + if r.rules == nil { + return make(map[string]core.RuleFunc) + } + return r.rules +} + +// RemoveRule removes a rule with the specified name from the rule set. +// If no rule with the specified name exists, it does nothing. +func (r *Rules) RemoveRule(name string) { + if r == nil { + return // impossible nonsense, hopefully + } + if r.rules != nil { + delete(r.rules, name) + } + + if len(r.ruleNameKeys) > 0 { + r.ruleNameKeys = slices.DeleteFunc(r.ruleNameKeys, func(s string) bool { + return s == name // delete the name rule key + }) + } +} + +// ReplaceRule replaces a rule with the specified name with a new rule function. +// If no rule with the specified name exists, it does nothing. +func (r *Rules) ReplaceRule(name string, ruleFunc core.RuleFunc) { + if r == nil { + return // impossible nonsense, hopefully + } + if r.rules == nil { + r.rules = make(map[string]core.RuleFunc) + } + if _, exists := r.rules[name]; exists { + r.rules[name] = ruleFunc + } +} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go index 73a1e89677..e4f210d757 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var ScalarLeafsRule = Rule{ @@ -37,7 +37,3 @@ var ScalarLeafsRule = Rule{ }) }, } - -func init() { - AddRule(ScalarLeafsRule.Name, ScalarLeafsRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go index 1498d82986..feed91d5ce 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go @@ -7,7 +7,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var SingleFieldSubscriptionsRule = Rule{ @@ -44,10 +44,6 @@ var SingleFieldSubscriptionsRule = Rule{ }, } -func init() { - AddRule(SingleFieldSubscriptionsRule.Name, SingleFieldSubscriptionsRule.RuleFunc) -} - type topField struct { name string position *ast.Position diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go index b90cc65107..2ed1da2b34 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var UniqueArgumentNamesRule = Rule{ @@ -20,10 +20,6 @@ var UniqueArgumentNamesRule = Rule{ }, } -func init() { - AddRule(UniqueArgumentNamesRule.Name, UniqueArgumentNamesRule.RuleFunc) -} - func checkUniqueArgs(args ast.ArgumentList, addError AddErrFunc) { knownArgNames := map[string]int{} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go index 4222f36aec..0f57702814 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var UniqueDirectivesPerLocationRule = Rule{ @@ -25,7 +25,3 @@ var UniqueDirectivesPerLocationRule = Rule{ }) }, } - -func init() { - AddRule(UniqueDirectivesPerLocationRule.Name, UniqueDirectivesPerLocationRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go index aab8eeb4eb..136b0fdb5a 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var UniqueFragmentNamesRule = Rule{ @@ -23,7 +23,3 @@ var UniqueFragmentNamesRule = Rule{ }) }, } - -func init() { - AddRule(UniqueFragmentNamesRule.Name, UniqueFragmentNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go index 250849344b..41d8d667aa 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var UniqueInputFieldNamesRule = Rule{ @@ -28,7 +28,3 @@ var UniqueInputFieldNamesRule = Rule{ }) }, } - -func init() { - AddRule(UniqueInputFieldNamesRule.Name, UniqueInputFieldNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go index 6f1ec26abf..ae4c54eede 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var UniqueOperationNamesRule = Rule{ @@ -23,7 +23,3 @@ var UniqueOperationNamesRule = Rule{ }) }, } - -func init() { - AddRule(UniqueOperationNamesRule.Name, UniqueOperationNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go index 6b037ed527..4d4a6a87f7 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var UniqueVariableNamesRule = Rule{ @@ -25,7 +25,3 @@ var UniqueVariableNamesRule = Rule{ }) }, } - -func init() { - AddRule(UniqueVariableNamesRule.Name, UniqueVariableNamesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go index 01510b7b5a..43c1a1bfb5 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go @@ -8,7 +8,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disableSuggestion bool) { @@ -213,10 +213,6 @@ var ValuesOfCorrectTypeRuleWithoutSuggestions = Rule{ }, } -func init() { - AddRule(ValuesOfCorrectTypeRule.Name, ValuesOfCorrectTypeRule.RuleFunc) -} - func unexpectedTypeMessage(addError AddErrFunc, v *ast.Value) { addError( unexpectedTypeMessageOnly(v), diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go index e1bf2b1f57..77f116bb50 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var VariablesAreInputTypesRule = Rule{ @@ -29,7 +29,3 @@ var VariablesAreInputTypesRule = Rule{ }) }, } - -func init() { - AddRule(VariablesAreInputTypesRule.Name, VariablesAreInputTypesRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go index f05ee687ad..b2af7e1923 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go @@ -4,7 +4,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. - . "github.com/vektah/gqlparser/v2/validator" + . "github.com/vektah/gqlparser/v2/validator/core" ) var VariablesInAllowedPositionRule = Rule{ @@ -39,7 +39,3 @@ var VariablesInAllowedPositionRule = Rule{ }) }, } - -func init() { - AddRule(VariablesInAllowedPositionRule.Name, VariablesInAllowedPositionRule.RuleFunc) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/suggestionList.go b/vendor/github.com/vektah/gqlparser/v2/validator/suggestionList.go deleted file mode 100644 index f0bbc32786..0000000000 --- a/vendor/github.com/vektah/gqlparser/v2/validator/suggestionList.go +++ /dev/null @@ -1,69 +0,0 @@ -package validator - -import ( - "math" - "sort" - "strings" - - "github.com/agnivade/levenshtein" -) - -// Given an invalid input string and a list of valid options, returns a filtered -// list of valid options sorted based on their similarity with the input. -func SuggestionList(input string, options []string) []string { - var results []string - optionsByDistance := map[string]int{} - - for _, option := range options { - distance := lexicalDistance(input, option) - threshold := calcThreshold(input) - if distance <= threshold { - results = append(results, option) - optionsByDistance[option] = distance - } - } - - sort.Slice(results, func(i, j int) bool { - return optionsByDistance[results[i]] < optionsByDistance[results[j]] - }) - return results -} - -func calcThreshold(a string) (threshold int) { - // the logic is copied from here - // https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/jsutils/suggestionList.ts#L14 - threshold = int(math.Floor(float64(len(a))*0.4) + 1) - - if threshold < 1 { - threshold = 1 - } - return -} - -// Computes the lexical distance between strings A and B. -// -// The "distance" between two strings is given by counting the minimum number -// of edits needed to transform string A into string B. An edit can be an -// insertion, deletion, or substitution of a single character, or a swap of two -// adjacent characters. -// -// Includes a custom alteration from Damerau-Levenshtein to treat case changes -// as a single edit which helps identify mis-cased values with an edit distance -// of 1. -// -// This distance can be useful for detecting typos in input or sorting -func lexicalDistance(a, b string) int { - if a == b { - return 0 - } - - a = strings.ToLower(a) - b = strings.ToLower(b) - - // Any case change counts as a single edit - if a == b { - return 1 - } - - return levenshtein.ComputeDistance(a, b) -} diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/validator.go b/vendor/github.com/vektah/gqlparser/v2/validator/validator.go index 1b4040c2c8..1214ed16e6 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/validator.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/validator.go @@ -1,22 +1,46 @@ package validator import ( + "sort" //nolint:staticcheck // bad, yeah . "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/validator/core" + validatorrules "github.com/vektah/gqlparser/v2/validator/rules" ) -type AddErrFunc func(options ...ErrorOption) +type ( + AddErrFunc = core.AddErrFunc + RuleFunc = core.RuleFunc + Rule = core.Rule + Events = core.Events + ErrorOption = core.ErrorOption + Walker = core.Walker +) -type RuleFunc func(observers *Events, addError AddErrFunc) +var ( + Message = core.Message + QuotedOrList = core.QuotedOrList + OrList = core.OrList +) -type Rule struct { - Name string - RuleFunc RuleFunc +// Walk is an alias for core.Walk +func Walk(schema *Schema, document *QueryDocument, observers *Events) { + core.Walk(schema, document, observers) } var specifiedRules []Rule +func init() { + // Initialize specifiedRules with default rules + defaultRules := validatorrules.NewDefaultRules() + for name, ruleFunc := range defaultRules.GetInner() { + specifiedRules = append(specifiedRules, Rule{Name: name, RuleFunc: ruleFunc}) + // ensure initial default is in deterministic order + sort.Sort(core.NameSorter(specifiedRules)) + } +} + // AddRule adds a rule to the rule set. // ruleFunc is called once each time `Validate` is executed. func AddRule(name string, ruleFunc RuleFunc) { @@ -59,6 +83,7 @@ func ReplaceRule(name string, ruleFunc RuleFunc) { specifiedRules = result } +// Deprecated: use ValidateWithRules instead. func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List { if rules == nil { rules = specifiedRules @@ -74,7 +99,7 @@ func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List { if len(errs) > 0 { return errs } - observers := &Events{} + observers := &core.Events{} for i := range rules { rule := rules[i] rule.RuleFunc(observers, func(options ...ErrorOption) { @@ -91,3 +116,43 @@ func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List { Walk(schema, doc, observers) return errs } + +func ValidateWithRules(schema *Schema, doc *QueryDocument, rules *validatorrules.Rules) gqlerror.List { + if rules == nil { + rules = validatorrules.NewDefaultRules() + } + + var errs gqlerror.List + if schema == nil { + errs = append(errs, gqlerror.Errorf("cannot validate as Schema is nil")) + } + if doc == nil { + errs = append(errs, gqlerror.Errorf("cannot validate as QueryDocument is nil")) + } + if len(errs) > 0 { + return errs + } + observers := &core.Events{} + + var currentRules []Rule // nolint:prealloc // would require extra local refs for len + for name, ruleFunc := range rules.GetInner() { + currentRules = append(currentRules, Rule{Name: name, RuleFunc: ruleFunc}) + // ensure deterministic order evaluation + sort.Sort(core.NameSorter(currentRules)) + } + + for _, currentRule := range currentRules { + currentRule.RuleFunc(observers, func(options ...ErrorOption) { + err := &gqlerror.Error{ + Rule: currentRule.Name, + } + for _, o := range options { + o(err) + } + errs = append(errs, err) + }) + } + + Walk(schema, doc, observers) + return errs +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cb177ee57b..f209c9ef30 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -342,6 +342,9 @@ github.com/davidbyttow/govips/v2/vips # github.com/deckarep/golang-set v1.8.0 ## explicit; go 1.17 github.com/deckarep/golang-set +# github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 +## explicit; go 1.17 +github.com/decred/dcrd/dcrec/secp256k1/v4 # github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f ## explicit github.com/desertbit/timer @@ -885,6 +888,54 @@ github.com/leodido/go-urn/scim/schema ## explicit; go 1.23.5 github.com/leonelquinteros/gotext github.com/leonelquinteros/gotext/plurals +# github.com/lestrrat-go/blackmagic v1.0.4 +## explicit; go 1.23 +github.com/lestrrat-go/blackmagic +# github.com/lestrrat-go/httpcc v1.0.1 +## explicit; go 1.16 +github.com/lestrrat-go/httpcc +# github.com/lestrrat-go/httprc/v3 v3.0.0 +## explicit; go 1.23 +github.com/lestrrat-go/httprc/v3 +github.com/lestrrat-go/httprc/v3/errsink +github.com/lestrrat-go/httprc/v3/proxysink +github.com/lestrrat-go/httprc/v3/tracesink +# github.com/lestrrat-go/jwx/v3 v3.0.10 +## explicit; go 1.23.0 +github.com/lestrrat-go/jwx/v3 +github.com/lestrrat-go/jwx/v3/cert +github.com/lestrrat-go/jwx/v3/internal/base64 +github.com/lestrrat-go/jwx/v3/internal/ecutil +github.com/lestrrat-go/jwx/v3/internal/json +github.com/lestrrat-go/jwx/v3/internal/jwxio +github.com/lestrrat-go/jwx/v3/internal/keyconv +github.com/lestrrat-go/jwx/v3/internal/pool +github.com/lestrrat-go/jwx/v3/internal/tokens +github.com/lestrrat-go/jwx/v3/jwa +github.com/lestrrat-go/jwx/v3/jwe +github.com/lestrrat-go/jwx/v3/jwe/internal/aescbc +github.com/lestrrat-go/jwx/v3/jwe/internal/cipher +github.com/lestrrat-go/jwx/v3/jwe/internal/concatkdf +github.com/lestrrat-go/jwx/v3/jwe/internal/content_crypt +github.com/lestrrat-go/jwx/v3/jwe/internal/keygen +github.com/lestrrat-go/jwx/v3/jwe/jwebb +github.com/lestrrat-go/jwx/v3/jwk +github.com/lestrrat-go/jwx/v3/jwk/ecdsa +github.com/lestrrat-go/jwx/v3/jwk/jwkbb +github.com/lestrrat-go/jwx/v3/jws +github.com/lestrrat-go/jwx/v3/jws/internal/keytype +github.com/lestrrat-go/jwx/v3/jws/jwsbb +github.com/lestrrat-go/jwx/v3/jws/legacy +github.com/lestrrat-go/jwx/v3/jwt +github.com/lestrrat-go/jwx/v3/jwt/internal/errors +github.com/lestrrat-go/jwx/v3/jwt/internal/types +github.com/lestrrat-go/jwx/v3/transform +# github.com/lestrrat-go/option v1.0.1 +## explicit; go 1.16 +github.com/lestrrat-go/option +# github.com/lestrrat-go/option/v2 v2.0.0 +## explicit; go 1.23 +github.com/lestrrat-go/option/v2 # github.com/libregraph/idm v0.5.0 ## explicit; go 1.21 github.com/libregraph/idm @@ -1178,8 +1229,8 @@ github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types -# github.com/open-policy-agent/opa v1.6.0 -## explicit; go 1.23.8 +# github.com/open-policy-agent/opa v1.8.0 +## explicit; go 1.24.6 github.com/open-policy-agent/opa/ast github.com/open-policy-agent/opa/ast/json github.com/open-policy-agent/opa/bundle @@ -1199,12 +1250,6 @@ github.com/open-policy-agent/opa/internal/file/url github.com/open-policy-agent/opa/internal/future github.com/open-policy-agent/opa/internal/gojsonschema github.com/open-policy-agent/opa/internal/json/patch -github.com/open-policy-agent/opa/internal/jwx/buffer -github.com/open-policy-agent/opa/internal/jwx/jwa -github.com/open-policy-agent/opa/internal/jwx/jwk -github.com/open-policy-agent/opa/internal/jwx/jws -github.com/open-policy-agent/opa/internal/jwx/jws/sign -github.com/open-policy-agent/opa/internal/jwx/jws/verify github.com/open-policy-agent/opa/internal/lcss github.com/open-policy-agent/opa/internal/leb128 github.com/open-policy-agent/opa/internal/merge @@ -1808,6 +1853,15 @@ github.com/russellhaering/goxmldsig/types # github.com/russross/blackfriday/v2 v2.1.0 ## explicit github.com/russross/blackfriday/v2 +# github.com/segmentio/asm v1.2.0 +## explicit; go 1.18 +github.com/segmentio/asm/base64 +github.com/segmentio/asm/cpu +github.com/segmentio/asm/cpu/arm +github.com/segmentio/asm/cpu/arm64 +github.com/segmentio/asm/cpu/cpuid +github.com/segmentio/asm/cpu/x86 +github.com/segmentio/asm/internal/unsafebytes # github.com/segmentio/kafka-go v0.4.49 ## explicit; go 1.23 github.com/segmentio/kafka-go @@ -1865,7 +1919,7 @@ github.com/segmentio/ksuid # github.com/sercand/kuberesolver/v5 v5.1.1 ## explicit; go 1.18 github.com/sercand/kuberesolver/v5 -# github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 +# github.com/sergi/go-diff v1.4.0 ## explicit; go 1.13 github.com/sergi/go-diff/diffmatchpatch # github.com/sethvargo/go-diceware v0.5.0 @@ -1933,7 +1987,7 @@ github.com/stretchr/testify/require # github.com/studio-b12/gowebdav v0.9.0 => github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 ## explicit; go 1.17 github.com/studio-b12/gowebdav -# github.com/tchap/go-patricia/v2 v2.3.2 +# github.com/tchap/go-patricia/v2 v2.3.3 ## explicit; go 1.16 github.com/tchap/go-patricia/v2/patricia # github.com/test-go/testify v1.1.4 @@ -2002,13 +2056,18 @@ github.com/unrolled/secure/cspbuilder # github.com/urfave/cli/v2 v2.27.7 ## explicit; go 1.18 github.com/urfave/cli/v2 -# github.com/vektah/gqlparser/v2 v2.5.28 +# github.com/valyala/fastjson v1.6.4 +## explicit; go 1.12 +github.com/valyala/fastjson +github.com/valyala/fastjson/fastfloat +# github.com/vektah/gqlparser/v2 v2.5.30 ## explicit; go 1.22 github.com/vektah/gqlparser/v2/ast github.com/vektah/gqlparser/v2/gqlerror github.com/vektah/gqlparser/v2/lexer github.com/vektah/gqlparser/v2/parser github.com/vektah/gqlparser/v2/validator +github.com/vektah/gqlparser/v2/validator/core github.com/vektah/gqlparser/v2/validator/rules # github.com/vmihailenco/msgpack/v5 v5.4.1 ## explicit; go 1.19 @@ -2586,10 +2645,9 @@ gotest.tools/v3/internal/assert gotest.tools/v3/internal/difflib gotest.tools/v3/internal/format gotest.tools/v3/internal/source -# sigs.k8s.io/yaml v1.4.0 -## explicit; go 1.12 +# sigs.k8s.io/yaml v1.6.0 +## explicit; go 1.22 sigs.k8s.io/yaml -sigs.k8s.io/yaml/goyaml.v2 # stash.kopano.io/kgol/rndm v1.1.2 ## explicit; go 1.13 stash.kopano.io/kgol/rndm diff --git a/vendor/sigs.k8s.io/yaml/.travis.yml b/vendor/sigs.k8s.io/yaml/.travis.yml deleted file mode 100644 index 54ed8f9cb9..0000000000 --- a/vendor/sigs.k8s.io/yaml/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go -arch: arm64 -dist: focal -go: 1.15.x -script: - - diff -u <(echo -n) <(gofmt -d *.go) - - diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON) - - GO111MODULE=on go vet . - - GO111MODULE=on go test -v -race ./... - - git diff --exit-code -install: - - GO111MODULE=off go get golang.org/x/lint/golint diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE b/vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE deleted file mode 100644 index 8dada3edaf..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/NOTICE b/vendor/sigs.k8s.io/yaml/goyaml.v2/NOTICE deleted file mode 100644 index 866d74a7ad..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2011-2016 Canonical Ltd. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/OWNERS b/vendor/sigs.k8s.io/yaml/goyaml.v2/OWNERS deleted file mode 100644 index 73be0a3a9b..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/OWNERS +++ /dev/null @@ -1,24 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -approvers: -- dims -- jpbetz -- smarterclayton -- deads2k -- sttts -- liggitt -- natasha41575 -- knverey -reviewers: -- dims -- thockin -- jpbetz -- smarterclayton -- deads2k -- derekwaynecarr -- mikedanese -- liggitt -- sttts -- tallclair -labels: -- sig/api-machinery diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/README.md b/vendor/sigs.k8s.io/yaml/goyaml.v2/README.md deleted file mode 100644 index 53f4139dc3..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/README.md +++ /dev/null @@ -1,143 +0,0 @@ -# go-yaml fork - -This package is a fork of the go-yaml library and is intended solely for consumption -by kubernetes projects. In this fork, we plan to support only critical changes required for -kubernetes, such as small bug fixes and regressions. Larger, general-purpose feature requests -should be made in the upstream go-yaml library, and we will reject such changes in this fork -unless we are pulling them from upstream. - -This fork is based on v2.4.0: https://github.com/go-yaml/yaml/releases/tag/v2.4.0 - -# YAML support for the Go language - -Introduction ------------- - -The yaml package enables Go programs to comfortably encode and decode YAML -values. It was developed within [Canonical](https://www.canonical.com) as -part of the [juju](https://juju.ubuntu.com) project, and is based on a -pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) -C library to parse and generate YAML data quickly and reliably. - -Compatibility -------------- - -The yaml package supports most of YAML 1.1 and 1.2, including support for -anchors, tags, map merging, etc. Multi-document unmarshalling is not yet -implemented, and base-60 floats from YAML 1.1 are purposefully not -supported since they're a poor design and are gone in YAML 1.2. - -Installation and usage ----------------------- - -The import path for the package is *gopkg.in/yaml.v2*. - -To install it, run: - - go get gopkg.in/yaml.v2 - -API documentation ------------------ - -If opened in a browser, the import path itself leads to the API documentation: - - * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) - -API stability -------------- - -The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). - - -License -------- - -The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. - - -Example -------- - -```Go -package main - -import ( - "fmt" - "log" - - "gopkg.in/yaml.v2" -) - -var data = ` -a: Easy! -b: - c: 2 - d: [3, 4] -` - -// Note: struct fields must be public in order for unmarshal to -// correctly populate the data. -type T struct { - A string - B struct { - RenamedC int `yaml:"c"` - D []int `yaml:",flow"` - } -} - -func main() { - t := T{} - - err := yaml.Unmarshal([]byte(data), &t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t:\n%v\n\n", t) - - d, err := yaml.Marshal(&t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t dump:\n%s\n\n", string(d)) - - m := make(map[interface{}]interface{}) - - err = yaml.Unmarshal([]byte(data), &m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m:\n%v\n\n", m) - - d, err = yaml.Marshal(&m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m dump:\n%s\n\n", string(d)) -} -``` - -This example will generate the following output: - -``` ---- t: -{Easy! {2 [3 4]}} - ---- t dump: -a: Easy! -b: - c: 2 - d: [3, 4] - - ---- m: -map[a:Easy! b:map[c:2 d:[3 4]]] - ---- m dump: -a: Easy! -b: - c: 2 - d: - - 3 - - 4 -``` - diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/apic.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/apic.go deleted file mode 100644 index acf71402cf..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/apic.go +++ /dev/null @@ -1,744 +0,0 @@ -package yaml - -import ( - "io" -) - -func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { - //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) - - // Check if we can move the queue at the beginning of the buffer. - if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { - if parser.tokens_head != len(parser.tokens) { - copy(parser.tokens, parser.tokens[parser.tokens_head:]) - } - parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] - parser.tokens_head = 0 - } - parser.tokens = append(parser.tokens, *token) - if pos < 0 { - return - } - copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) - parser.tokens[parser.tokens_head+pos] = *token -} - -// Create a new parser object. -func yaml_parser_initialize(parser *yaml_parser_t) bool { - *parser = yaml_parser_t{ - raw_buffer: make([]byte, 0, input_raw_buffer_size), - buffer: make([]byte, 0, input_buffer_size), - } - return true -} - -// Destroy a parser object. -func yaml_parser_delete(parser *yaml_parser_t) { - *parser = yaml_parser_t{} -} - -// String read handler. -func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - if parser.input_pos == len(parser.input) { - return 0, io.EOF - } - n = copy(buffer, parser.input[parser.input_pos:]) - parser.input_pos += n - return n, nil -} - -// Reader read handler. -func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - return parser.input_reader.Read(buffer) -} - -// Set a string input. -func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_string_read_handler - parser.input = input - parser.input_pos = 0 -} - -// Set a file input. -func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_reader_read_handler - parser.input_reader = r -} - -// Set the source encoding. -func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { - if parser.encoding != yaml_ANY_ENCODING { - panic("must set the encoding only once") - } - parser.encoding = encoding -} - -var disableLineWrapping = false - -// Create a new emitter object. -func yaml_emitter_initialize(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{ - buffer: make([]byte, output_buffer_size), - raw_buffer: make([]byte, 0, output_raw_buffer_size), - states: make([]yaml_emitter_state_t, 0, initial_stack_size), - events: make([]yaml_event_t, 0, initial_queue_size), - } - if disableLineWrapping { - emitter.best_width = -1 - } -} - -// Destroy an emitter object. -func yaml_emitter_delete(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{} -} - -// String write handler. -func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - *emitter.output_buffer = append(*emitter.output_buffer, buffer...) - return nil -} - -// yaml_writer_write_handler uses emitter.output_writer to write the -// emitted text. -func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - _, err := emitter.output_writer.Write(buffer) - return err -} - -// Set a string output. -func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_string_write_handler - emitter.output_buffer = output_buffer -} - -// Set a file output. -func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_writer_write_handler - emitter.output_writer = w -} - -// Set the output encoding. -func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { - if emitter.encoding != yaml_ANY_ENCODING { - panic("must set the output encoding only once") - } - emitter.encoding = encoding -} - -// Set the canonical output style. -func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { - emitter.canonical = canonical -} - -//// Set the indentation increment. -func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { - if indent < 2 || indent > 9 { - indent = 2 - } - emitter.best_indent = indent -} - -// Set the preferred line width. -func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { - if width < 0 { - width = -1 - } - emitter.best_width = width -} - -// Set if unescaped non-ASCII characters are allowed. -func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { - emitter.unicode = unicode -} - -// Set the preferred line break character. -func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { - emitter.line_break = line_break -} - -///* -// * Destroy a token object. -// */ -// -//YAML_DECLARE(void) -//yaml_token_delete(yaml_token_t *token) -//{ -// assert(token); // Non-NULL token object expected. -// -// switch (token.type) -// { -// case YAML_TAG_DIRECTIVE_TOKEN: -// yaml_free(token.data.tag_directive.handle); -// yaml_free(token.data.tag_directive.prefix); -// break; -// -// case YAML_ALIAS_TOKEN: -// yaml_free(token.data.alias.value); -// break; -// -// case YAML_ANCHOR_TOKEN: -// yaml_free(token.data.anchor.value); -// break; -// -// case YAML_TAG_TOKEN: -// yaml_free(token.data.tag.handle); -// yaml_free(token.data.tag.suffix); -// break; -// -// case YAML_SCALAR_TOKEN: -// yaml_free(token.data.scalar.value); -// break; -// -// default: -// break; -// } -// -// memset(token, 0, sizeof(yaml_token_t)); -//} -// -///* -// * Check if a string is a valid UTF-8 sequence. -// * -// * Check 'reader.c' for more details on UTF-8 encoding. -// */ -// -//static int -//yaml_check_utf8(yaml_char_t *start, size_t length) -//{ -// yaml_char_t *end = start+length; -// yaml_char_t *pointer = start; -// -// while (pointer < end) { -// unsigned char octet; -// unsigned int width; -// unsigned int value; -// size_t k; -// -// octet = pointer[0]; -// width = (octet & 0x80) == 0x00 ? 1 : -// (octet & 0xE0) == 0xC0 ? 2 : -// (octet & 0xF0) == 0xE0 ? 3 : -// (octet & 0xF8) == 0xF0 ? 4 : 0; -// value = (octet & 0x80) == 0x00 ? octet & 0x7F : -// (octet & 0xE0) == 0xC0 ? octet & 0x1F : -// (octet & 0xF0) == 0xE0 ? octet & 0x0F : -// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; -// if (!width) return 0; -// if (pointer+width > end) return 0; -// for (k = 1; k < width; k ++) { -// octet = pointer[k]; -// if ((octet & 0xC0) != 0x80) return 0; -// value = (value << 6) + (octet & 0x3F); -// } -// if (!((width == 1) || -// (width == 2 && value >= 0x80) || -// (width == 3 && value >= 0x800) || -// (width == 4 && value >= 0x10000))) return 0; -// -// pointer += width; -// } -// -// return 1; -//} -// - -// Create STREAM-START. -func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - encoding: encoding, - } -} - -// Create STREAM-END. -func yaml_stream_end_event_initialize(event *yaml_event_t) { - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - } -} - -// Create DOCUMENT-START. -func yaml_document_start_event_initialize( - event *yaml_event_t, - version_directive *yaml_version_directive_t, - tag_directives []yaml_tag_directive_t, - implicit bool, -) { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: implicit, - } -} - -// Create DOCUMENT-END. -func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - implicit: implicit, - } -} - -///* -// * Create ALIAS. -// */ -// -//YAML_DECLARE(int) -//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) -//{ -// mark yaml_mark_t = { 0, 0, 0 } -// anchor_copy *yaml_char_t = NULL -// -// assert(event) // Non-NULL event object is expected. -// assert(anchor) // Non-NULL anchor is expected. -// -// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 -// -// anchor_copy = yaml_strdup(anchor) -// if (!anchor_copy) -// return 0 -// -// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) -// -// return 1 -//} - -// Create SCALAR. -func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - anchor: anchor, - tag: tag, - value: value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-START. -func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-END. -func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - } - return true -} - -// Create MAPPING-START. -func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } -} - -// Create MAPPING-END. -func yaml_mapping_end_event_initialize(event *yaml_event_t) { - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - } -} - -// Destroy an event object. -func yaml_event_delete(event *yaml_event_t) { - *event = yaml_event_t{} -} - -///* -// * Create a document object. -// */ -// -//YAML_DECLARE(int) -//yaml_document_initialize(document *yaml_document_t, -// version_directive *yaml_version_directive_t, -// tag_directives_start *yaml_tag_directive_t, -// tag_directives_end *yaml_tag_directive_t, -// start_implicit int, end_implicit int) -//{ -// struct { -// error yaml_error_type_t -// } context -// struct { -// start *yaml_node_t -// end *yaml_node_t -// top *yaml_node_t -// } nodes = { NULL, NULL, NULL } -// version_directive_copy *yaml_version_directive_t = NULL -// struct { -// start *yaml_tag_directive_t -// end *yaml_tag_directive_t -// top *yaml_tag_directive_t -// } tag_directives_copy = { NULL, NULL, NULL } -// value yaml_tag_directive_t = { NULL, NULL } -// mark yaml_mark_t = { 0, 0, 0 } -// -// assert(document) // Non-NULL document object is expected. -// assert((tag_directives_start && tag_directives_end) || -// (tag_directives_start == tag_directives_end)) -// // Valid tag directives are expected. -// -// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error -// -// if (version_directive) { -// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) -// if (!version_directive_copy) goto error -// version_directive_copy.major = version_directive.major -// version_directive_copy.minor = version_directive.minor -// } -// -// if (tag_directives_start != tag_directives_end) { -// tag_directive *yaml_tag_directive_t -// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) -// goto error -// for (tag_directive = tag_directives_start -// tag_directive != tag_directives_end; tag_directive ++) { -// assert(tag_directive.handle) -// assert(tag_directive.prefix) -// if (!yaml_check_utf8(tag_directive.handle, -// strlen((char *)tag_directive.handle))) -// goto error -// if (!yaml_check_utf8(tag_directive.prefix, -// strlen((char *)tag_directive.prefix))) -// goto error -// value.handle = yaml_strdup(tag_directive.handle) -// value.prefix = yaml_strdup(tag_directive.prefix) -// if (!value.handle || !value.prefix) goto error -// if (!PUSH(&context, tag_directives_copy, value)) -// goto error -// value.handle = NULL -// value.prefix = NULL -// } -// } -// -// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, -// tag_directives_copy.start, tag_directives_copy.top, -// start_implicit, end_implicit, mark, mark) -// -// return 1 -// -//error: -// STACK_DEL(&context, nodes) -// yaml_free(version_directive_copy) -// while (!STACK_EMPTY(&context, tag_directives_copy)) { -// value yaml_tag_directive_t = POP(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// } -// STACK_DEL(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// -// return 0 -//} -// -///* -// * Destroy a document object. -// */ -// -//YAML_DECLARE(void) -//yaml_document_delete(document *yaml_document_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// tag_directive *yaml_tag_directive_t -// -// context.error = YAML_NO_ERROR // Eliminate a compiler warning. -// -// assert(document) // Non-NULL document object is expected. -// -// while (!STACK_EMPTY(&context, document.nodes)) { -// node yaml_node_t = POP(&context, document.nodes) -// yaml_free(node.tag) -// switch (node.type) { -// case YAML_SCALAR_NODE: -// yaml_free(node.data.scalar.value) -// break -// case YAML_SEQUENCE_NODE: -// STACK_DEL(&context, node.data.sequence.items) -// break -// case YAML_MAPPING_NODE: -// STACK_DEL(&context, node.data.mapping.pairs) -// break -// default: -// assert(0) // Should not happen. -// } -// } -// STACK_DEL(&context, document.nodes) -// -// yaml_free(document.version_directive) -// for (tag_directive = document.tag_directives.start -// tag_directive != document.tag_directives.end -// tag_directive++) { -// yaml_free(tag_directive.handle) -// yaml_free(tag_directive.prefix) -// } -// yaml_free(document.tag_directives.start) -// -// memset(document, 0, sizeof(yaml_document_t)) -//} -// -///** -// * Get a document node. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_node(document *yaml_document_t, index int) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (index > 0 && document.nodes.start + index <= document.nodes.top) { -// return document.nodes.start + index - 1 -// } -// return NULL -//} -// -///** -// * Get the root object. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_root_node(document *yaml_document_t) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (document.nodes.top != document.nodes.start) { -// return document.nodes.start -// } -// return NULL -//} -// -///* -// * Add a scalar node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_scalar(document *yaml_document_t, -// tag *yaml_char_t, value *yaml_char_t, length int, -// style yaml_scalar_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// value_copy *yaml_char_t = NULL -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// assert(value) // Non-NULL value is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (length < 0) { -// length = strlen((char *)value) -// } -// -// if (!yaml_check_utf8(value, length)) goto error -// value_copy = yaml_malloc(length+1) -// if (!value_copy) goto error -// memcpy(value_copy, value, length) -// value_copy[length] = '\0' -// -// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// yaml_free(tag_copy) -// yaml_free(value_copy) -// -// return 0 -//} -// -///* -// * Add a sequence node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_sequence(document *yaml_document_t, -// tag *yaml_char_t, style yaml_sequence_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_item_t -// end *yaml_node_item_t -// top *yaml_node_item_t -// } items = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error -// -// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, items) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Add a mapping node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_mapping(document *yaml_document_t, -// tag *yaml_char_t, style yaml_mapping_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_pair_t -// end *yaml_node_pair_t -// top *yaml_node_pair_t -// } pairs = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error -// -// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, pairs) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Append an item to a sequence node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_sequence_item(document *yaml_document_t, -// sequence int, item int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// assert(document) // Non-NULL document is required. -// assert(sequence > 0 -// && document.nodes.start + sequence <= document.nodes.top) -// // Valid sequence id is required. -// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) -// // A sequence node is required. -// assert(item > 0 && document.nodes.start + item <= document.nodes.top) -// // Valid item id is required. -// -// if (!PUSH(&context, -// document.nodes.start[sequence-1].data.sequence.items, item)) -// return 0 -// -// return 1 -//} -// -///* -// * Append a pair of a key and a value to a mapping node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_mapping_pair(document *yaml_document_t, -// mapping int, key int, value int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// pair yaml_node_pair_t -// -// assert(document) // Non-NULL document is required. -// assert(mapping > 0 -// && document.nodes.start + mapping <= document.nodes.top) -// // Valid mapping id is required. -// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) -// // A mapping node is required. -// assert(key > 0 && document.nodes.start + key <= document.nodes.top) -// // Valid key id is required. -// assert(value > 0 && document.nodes.start + value <= document.nodes.top) -// // Valid value id is required. -// -// pair.key = key -// pair.value = value -// -// if (!PUSH(&context, -// document.nodes.start[mapping-1].data.mapping.pairs, pair)) -// return 0 -// -// return 1 -//} -// -// diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/decode.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/decode.go deleted file mode 100644 index 129bc2a97d..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/decode.go +++ /dev/null @@ -1,815 +0,0 @@ -package yaml - -import ( - "encoding" - "encoding/base64" - "fmt" - "io" - "math" - "reflect" - "strconv" - "time" -) - -const ( - documentNode = 1 << iota - mappingNode - sequenceNode - scalarNode - aliasNode -) - -type node struct { - kind int - line, column int - tag string - // For an alias node, alias holds the resolved alias. - alias *node - value string - implicit bool - children []*node - anchors map[string]*node -} - -// ---------------------------------------------------------------------------- -// Parser, produces a node tree out of a libyaml event stream. - -type parser struct { - parser yaml_parser_t - event yaml_event_t - doc *node - doneInit bool -} - -func newParser(b []byte) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - if len(b) == 0 { - b = []byte{'\n'} - } - yaml_parser_set_input_string(&p.parser, b) - return &p -} - -func newParserFromReader(r io.Reader) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - yaml_parser_set_input_reader(&p.parser, r) - return &p -} - -func (p *parser) init() { - if p.doneInit { - return - } - p.expect(yaml_STREAM_START_EVENT) - p.doneInit = true -} - -func (p *parser) destroy() { - if p.event.typ != yaml_NO_EVENT { - yaml_event_delete(&p.event) - } - yaml_parser_delete(&p.parser) -} - -// expect consumes an event from the event stream and -// checks that it's of the expected type. -func (p *parser) expect(e yaml_event_type_t) { - if p.event.typ == yaml_NO_EVENT { - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } - } - if p.event.typ == yaml_STREAM_END_EVENT { - failf("attempted to go past the end of stream; corrupted value?") - } - if p.event.typ != e { - p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) - p.fail() - } - yaml_event_delete(&p.event) - p.event.typ = yaml_NO_EVENT -} - -// peek peeks at the next event in the event stream, -// puts the results into p.event and returns the event type. -func (p *parser) peek() yaml_event_type_t { - if p.event.typ != yaml_NO_EVENT { - return p.event.typ - } - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } - return p.event.typ -} - -func (p *parser) fail() { - var where string - var line int - if p.parser.problem_mark.line != 0 { - line = p.parser.problem_mark.line - // Scanner errors don't iterate line before returning error - if p.parser.error == yaml_SCANNER_ERROR { - line++ - } - } else if p.parser.context_mark.line != 0 { - line = p.parser.context_mark.line - } - if line != 0 { - where = "line " + strconv.Itoa(line) + ": " - } - var msg string - if len(p.parser.problem) > 0 { - msg = p.parser.problem - } else { - msg = "unknown problem parsing YAML content" - } - failf("%s%s", where, msg) -} - -func (p *parser) anchor(n *node, anchor []byte) { - if anchor != nil { - p.doc.anchors[string(anchor)] = n - } -} - -func (p *parser) parse() *node { - p.init() - switch p.peek() { - case yaml_SCALAR_EVENT: - return p.scalar() - case yaml_ALIAS_EVENT: - return p.alias() - case yaml_MAPPING_START_EVENT: - return p.mapping() - case yaml_SEQUENCE_START_EVENT: - return p.sequence() - case yaml_DOCUMENT_START_EVENT: - return p.document() - case yaml_STREAM_END_EVENT: - // Happens when attempting to decode an empty buffer. - return nil - default: - panic("attempted to parse unknown event: " + p.event.typ.String()) - } -} - -func (p *parser) node(kind int) *node { - return &node{ - kind: kind, - line: p.event.start_mark.line, - column: p.event.start_mark.column, - } -} - -func (p *parser) document() *node { - n := p.node(documentNode) - n.anchors = make(map[string]*node) - p.doc = n - p.expect(yaml_DOCUMENT_START_EVENT) - n.children = append(n.children, p.parse()) - p.expect(yaml_DOCUMENT_END_EVENT) - return n -} - -func (p *parser) alias() *node { - n := p.node(aliasNode) - n.value = string(p.event.anchor) - n.alias = p.doc.anchors[n.value] - if n.alias == nil { - failf("unknown anchor '%s' referenced", n.value) - } - p.expect(yaml_ALIAS_EVENT) - return n -} - -func (p *parser) scalar() *node { - n := p.node(scalarNode) - n.value = string(p.event.value) - n.tag = string(p.event.tag) - n.implicit = p.event.implicit - p.anchor(n, p.event.anchor) - p.expect(yaml_SCALAR_EVENT) - return n -} - -func (p *parser) sequence() *node { - n := p.node(sequenceNode) - p.anchor(n, p.event.anchor) - p.expect(yaml_SEQUENCE_START_EVENT) - for p.peek() != yaml_SEQUENCE_END_EVENT { - n.children = append(n.children, p.parse()) - } - p.expect(yaml_SEQUENCE_END_EVENT) - return n -} - -func (p *parser) mapping() *node { - n := p.node(mappingNode) - p.anchor(n, p.event.anchor) - p.expect(yaml_MAPPING_START_EVENT) - for p.peek() != yaml_MAPPING_END_EVENT { - n.children = append(n.children, p.parse(), p.parse()) - } - p.expect(yaml_MAPPING_END_EVENT) - return n -} - -// ---------------------------------------------------------------------------- -// Decoder, unmarshals a node into a provided value. - -type decoder struct { - doc *node - aliases map[*node]bool - mapType reflect.Type - terrors []string - strict bool - - decodeCount int - aliasCount int - aliasDepth int -} - -var ( - mapItemType = reflect.TypeOf(MapItem{}) - durationType = reflect.TypeOf(time.Duration(0)) - defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) - ifaceType = defaultMapType.Elem() - timeType = reflect.TypeOf(time.Time{}) - ptrTimeType = reflect.TypeOf(&time.Time{}) -) - -func newDecoder(strict bool) *decoder { - d := &decoder{mapType: defaultMapType, strict: strict} - d.aliases = make(map[*node]bool) - return d -} - -func (d *decoder) terror(n *node, tag string, out reflect.Value) { - if n.tag != "" { - tag = n.tag - } - value := n.value - if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { - if len(value) > 10 { - value = " `" + value[:7] + "...`" - } else { - value = " `" + value + "`" - } - } - d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) -} - -func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { - terrlen := len(d.terrors) - err := u.UnmarshalYAML(func(v interface{}) (err error) { - defer handleErr(&err) - d.unmarshal(n, reflect.ValueOf(v)) - if len(d.terrors) > terrlen { - issues := d.terrors[terrlen:] - d.terrors = d.terrors[:terrlen] - return &TypeError{issues} - } - return nil - }) - if e, ok := err.(*TypeError); ok { - d.terrors = append(d.terrors, e.Errors...) - return false - } - if err != nil { - fail(err) - } - return true -} - -// d.prepare initializes and dereferences pointers and calls UnmarshalYAML -// if a value is found to implement it. -// It returns the initialized and dereferenced out value, whether -// unmarshalling was already done by UnmarshalYAML, and if so whether -// its types unmarshalled appropriately. -// -// If n holds a null value, prepare returns before doing anything. -func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { - if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { - return out, false, false - } - again := true - for again { - again = false - if out.Kind() == reflect.Ptr { - if out.IsNil() { - out.Set(reflect.New(out.Type().Elem())) - } - out = out.Elem() - again = true - } - if out.CanAddr() { - if u, ok := out.Addr().Interface().(Unmarshaler); ok { - good = d.callUnmarshaler(n, u) - return out, true, good - } - } - } - return out, false, false -} - -const ( - // 400,000 decode operations is ~500kb of dense object declarations, or - // ~5kb of dense object declarations with 10000% alias expansion - alias_ratio_range_low = 400000 - - // 4,000,000 decode operations is ~5MB of dense object declarations, or - // ~4.5MB of dense object declarations with 10% alias expansion - alias_ratio_range_high = 4000000 - - // alias_ratio_range is the range over which we scale allowed alias ratios - alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low) -) - -func allowedAliasRatio(decodeCount int) float64 { - switch { - case decodeCount <= alias_ratio_range_low: - // allow 99% to come from alias expansion for small-to-medium documents - return 0.99 - case decodeCount >= alias_ratio_range_high: - // allow 10% to come from alias expansion for very large documents - return 0.10 - default: - // scale smoothly from 99% down to 10% over the range. - // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range. - // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps). - return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range) - } -} - -func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { - d.decodeCount++ - if d.aliasDepth > 0 { - d.aliasCount++ - } - if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) { - failf("document contains excessive aliasing") - } - switch n.kind { - case documentNode: - return d.document(n, out) - case aliasNode: - return d.alias(n, out) - } - out, unmarshaled, good := d.prepare(n, out) - if unmarshaled { - return good - } - switch n.kind { - case scalarNode: - good = d.scalar(n, out) - case mappingNode: - good = d.mapping(n, out) - case sequenceNode: - good = d.sequence(n, out) - default: - panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) - } - return good -} - -func (d *decoder) document(n *node, out reflect.Value) (good bool) { - if len(n.children) == 1 { - d.doc = n - d.unmarshal(n.children[0], out) - return true - } - return false -} - -func (d *decoder) alias(n *node, out reflect.Value) (good bool) { - if d.aliases[n] { - // TODO this could actually be allowed in some circumstances. - failf("anchor '%s' value contains itself", n.value) - } - d.aliases[n] = true - d.aliasDepth++ - good = d.unmarshal(n.alias, out) - d.aliasDepth-- - delete(d.aliases, n) - return good -} - -var zeroValue reflect.Value - -func resetMap(out reflect.Value) { - for _, k := range out.MapKeys() { - out.SetMapIndex(k, zeroValue) - } -} - -func (d *decoder) scalar(n *node, out reflect.Value) bool { - var tag string - var resolved interface{} - if n.tag == "" && !n.implicit { - tag = yaml_STR_TAG - resolved = n.value - } else { - tag, resolved = resolve(n.tag, n.value) - if tag == yaml_BINARY_TAG { - data, err := base64.StdEncoding.DecodeString(resolved.(string)) - if err != nil { - failf("!!binary value contains invalid base64 data") - } - resolved = string(data) - } - } - if resolved == nil { - if out.Kind() == reflect.Map && !out.CanAddr() { - resetMap(out) - } else { - out.Set(reflect.Zero(out.Type())) - } - return true - } - if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { - // We've resolved to exactly the type we want, so use that. - out.Set(resolvedv) - return true - } - // Perhaps we can use the value as a TextUnmarshaler to - // set its value. - if out.CanAddr() { - u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) - if ok { - var text []byte - if tag == yaml_BINARY_TAG { - text = []byte(resolved.(string)) - } else { - // We let any value be unmarshaled into TextUnmarshaler. - // That might be more lax than we'd like, but the - // TextUnmarshaler itself should bowl out any dubious values. - text = []byte(n.value) - } - err := u.UnmarshalText(text) - if err != nil { - fail(err) - } - return true - } - } - switch out.Kind() { - case reflect.String: - if tag == yaml_BINARY_TAG { - out.SetString(resolved.(string)) - return true - } - if resolved != nil { - out.SetString(n.value) - return true - } - case reflect.Interface: - if resolved == nil { - out.Set(reflect.Zero(out.Type())) - } else if tag == yaml_TIMESTAMP_TAG { - // It looks like a timestamp but for backward compatibility - // reasons we set it as a string, so that code that unmarshals - // timestamp-like values into interface{} will continue to - // see a string and not a time.Time. - // TODO(v3) Drop this. - out.Set(reflect.ValueOf(n.value)) - } else { - out.Set(reflect.ValueOf(resolved)) - } - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch resolved := resolved.(type) { - case int: - if !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case int64: - if !out.OverflowInt(resolved) { - out.SetInt(resolved) - return true - } - case uint64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case float64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case string: - if out.Type() == durationType { - d, err := time.ParseDuration(resolved) - if err == nil { - out.SetInt(int64(d)) - return true - } - } - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - switch resolved := resolved.(type) { - case int: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case int64: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case uint64: - if !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case float64: - if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - } - case reflect.Bool: - switch resolved := resolved.(type) { - case bool: - out.SetBool(resolved) - return true - } - case reflect.Float32, reflect.Float64: - switch resolved := resolved.(type) { - case int: - out.SetFloat(float64(resolved)) - return true - case int64: - out.SetFloat(float64(resolved)) - return true - case uint64: - out.SetFloat(float64(resolved)) - return true - case float64: - out.SetFloat(resolved) - return true - } - case reflect.Struct: - if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { - out.Set(resolvedv) - return true - } - case reflect.Ptr: - if out.Type().Elem() == reflect.TypeOf(resolved) { - // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? - elem := reflect.New(out.Type().Elem()) - elem.Elem().Set(reflect.ValueOf(resolved)) - out.Set(elem) - return true - } - } - d.terror(n, tag, out) - return false -} - -func settableValueOf(i interface{}) reflect.Value { - v := reflect.ValueOf(i) - sv := reflect.New(v.Type()).Elem() - sv.Set(v) - return sv -} - -func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { - l := len(n.children) - - var iface reflect.Value - switch out.Kind() { - case reflect.Slice: - out.Set(reflect.MakeSlice(out.Type(), l, l)) - case reflect.Array: - if l != out.Len() { - failf("invalid array: want %d elements but got %d", out.Len(), l) - } - case reflect.Interface: - // No type hints. Will have to use a generic sequence. - iface = out - out = settableValueOf(make([]interface{}, l)) - default: - d.terror(n, yaml_SEQ_TAG, out) - return false - } - et := out.Type().Elem() - - j := 0 - for i := 0; i < l; i++ { - e := reflect.New(et).Elem() - if ok := d.unmarshal(n.children[i], e); ok { - out.Index(j).Set(e) - j++ - } - } - if out.Kind() != reflect.Array { - out.Set(out.Slice(0, j)) - } - if iface.IsValid() { - iface.Set(out) - } - return true -} - -func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { - switch out.Kind() { - case reflect.Struct: - return d.mappingStruct(n, out) - case reflect.Slice: - return d.mappingSlice(n, out) - case reflect.Map: - // okay - case reflect.Interface: - if d.mapType.Kind() == reflect.Map { - iface := out - out = reflect.MakeMap(d.mapType) - iface.Set(out) - } else { - slicev := reflect.New(d.mapType).Elem() - if !d.mappingSlice(n, slicev) { - return false - } - out.Set(slicev) - return true - } - default: - d.terror(n, yaml_MAP_TAG, out) - return false - } - outt := out.Type() - kt := outt.Key() - et := outt.Elem() - - mapType := d.mapType - if outt.Key() == ifaceType && outt.Elem() == ifaceType { - d.mapType = outt - } - - if out.IsNil() { - out.Set(reflect.MakeMap(outt)) - } - l := len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - k := reflect.New(kt).Elem() - if d.unmarshal(n.children[i], k) { - kkind := k.Kind() - if kkind == reflect.Interface { - kkind = k.Elem().Kind() - } - if kkind == reflect.Map || kkind == reflect.Slice { - failf("invalid map key: %#v", k.Interface()) - } - e := reflect.New(et).Elem() - if d.unmarshal(n.children[i+1], e) { - d.setMapIndex(n.children[i+1], out, k, e) - } - } - } - d.mapType = mapType - return true -} - -func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { - if d.strict && out.MapIndex(k) != zeroValue { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) - return - } - out.SetMapIndex(k, v) -} - -func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { - outt := out.Type() - if outt.Elem() != mapItemType { - d.terror(n, yaml_MAP_TAG, out) - return false - } - - mapType := d.mapType - d.mapType = outt - - var slice []MapItem - var l = len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - item := MapItem{} - k := reflect.ValueOf(&item.Key).Elem() - if d.unmarshal(n.children[i], k) { - v := reflect.ValueOf(&item.Value).Elem() - if d.unmarshal(n.children[i+1], v) { - slice = append(slice, item) - } - } - } - out.Set(reflect.ValueOf(slice)) - d.mapType = mapType - return true -} - -func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { - sinfo, err := getStructInfo(out.Type()) - if err != nil { - panic(err) - } - name := settableValueOf("") - l := len(n.children) - - var inlineMap reflect.Value - var elemType reflect.Type - if sinfo.InlineMap != -1 { - inlineMap = out.Field(sinfo.InlineMap) - inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) - elemType = inlineMap.Type().Elem() - } - - var doneFields []bool - if d.strict { - doneFields = make([]bool, len(sinfo.FieldsList)) - } - for i := 0; i < l; i += 2 { - ni := n.children[i] - if isMerge(ni) { - d.merge(n.children[i+1], out) - continue - } - if !d.unmarshal(ni, name) { - continue - } - if info, ok := sinfo.FieldsMap[name.String()]; ok { - if d.strict { - if doneFields[info.Id] { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) - continue - } - doneFields[info.Id] = true - } - var field reflect.Value - if info.Inline == nil { - field = out.Field(info.Num) - } else { - field = out.FieldByIndex(info.Inline) - } - d.unmarshal(n.children[i+1], field) - } else if sinfo.InlineMap != -1 { - if inlineMap.IsNil() { - inlineMap.Set(reflect.MakeMap(inlineMap.Type())) - } - value := reflect.New(elemType).Elem() - d.unmarshal(n.children[i+1], value) - d.setMapIndex(n.children[i+1], inlineMap, name, value) - } else if d.strict { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) - } - } - return true -} - -func failWantMap() { - failf("map merge requires map or sequence of maps as the value") -} - -func (d *decoder) merge(n *node, out reflect.Value) { - switch n.kind { - case mappingNode: - d.unmarshal(n, out) - case aliasNode: - if n.alias != nil && n.alias.kind != mappingNode { - failWantMap() - } - d.unmarshal(n, out) - case sequenceNode: - // Step backwards as earlier nodes take precedence. - for i := len(n.children) - 1; i >= 0; i-- { - ni := n.children[i] - if ni.kind == aliasNode { - if ni.alias != nil && ni.alias.kind != mappingNode { - failWantMap() - } - } else if ni.kind != mappingNode { - failWantMap() - } - d.unmarshal(ni, out) - } - default: - failWantMap() - } -} - -func isMerge(n *node) bool { - return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/emitterc.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/emitterc.go deleted file mode 100644 index a1c2cc5262..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/emitterc.go +++ /dev/null @@ -1,1685 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Flush the buffer if needed. -func flush(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) { - return yaml_emitter_flush(emitter) - } - return true -} - -// Put a character to the output buffer. -func put(emitter *yaml_emitter_t, value byte) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - emitter.buffer[emitter.buffer_pos] = value - emitter.buffer_pos++ - emitter.column++ - return true -} - -// Put a line break to the output buffer. -func put_break(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - switch emitter.line_break { - case yaml_CR_BREAK: - emitter.buffer[emitter.buffer_pos] = '\r' - emitter.buffer_pos += 1 - case yaml_LN_BREAK: - emitter.buffer[emitter.buffer_pos] = '\n' - emitter.buffer_pos += 1 - case yaml_CRLN_BREAK: - emitter.buffer[emitter.buffer_pos+0] = '\r' - emitter.buffer[emitter.buffer_pos+1] = '\n' - emitter.buffer_pos += 2 - default: - panic("unknown line break setting") - } - emitter.column = 0 - emitter.line++ - return true -} - -// Copy a character from a string into buffer. -func write(emitter *yaml_emitter_t, s []byte, i *int) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - p := emitter.buffer_pos - w := width(s[*i]) - switch w { - case 4: - emitter.buffer[p+3] = s[*i+3] - fallthrough - case 3: - emitter.buffer[p+2] = s[*i+2] - fallthrough - case 2: - emitter.buffer[p+1] = s[*i+1] - fallthrough - case 1: - emitter.buffer[p+0] = s[*i+0] - default: - panic("unknown character width") - } - emitter.column++ - emitter.buffer_pos += w - *i += w - return true -} - -// Write a whole string into buffer. -func write_all(emitter *yaml_emitter_t, s []byte) bool { - for i := 0; i < len(s); { - if !write(emitter, s, &i) { - return false - } - } - return true -} - -// Copy a line break character from a string into buffer. -func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { - if s[*i] == '\n' { - if !put_break(emitter) { - return false - } - *i++ - } else { - if !write(emitter, s, i) { - return false - } - emitter.column = 0 - emitter.line++ - } - return true -} - -// Set an emitter error and return false. -func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_EMITTER_ERROR - emitter.problem = problem - return false -} - -// Emit an event. -func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.events = append(emitter.events, *event) - for !yaml_emitter_need_more_events(emitter) { - event := &emitter.events[emitter.events_head] - if !yaml_emitter_analyze_event(emitter, event) { - return false - } - if !yaml_emitter_state_machine(emitter, event) { - return false - } - yaml_event_delete(event) - emitter.events_head++ - } - return true -} - -// Check if we need to accumulate more events before emitting. -// -// We accumulate extra -// - 1 event for DOCUMENT-START -// - 2 events for SEQUENCE-START -// - 3 events for MAPPING-START -// -func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { - if emitter.events_head == len(emitter.events) { - return true - } - var accumulate int - switch emitter.events[emitter.events_head].typ { - case yaml_DOCUMENT_START_EVENT: - accumulate = 1 - break - case yaml_SEQUENCE_START_EVENT: - accumulate = 2 - break - case yaml_MAPPING_START_EVENT: - accumulate = 3 - break - default: - return false - } - if len(emitter.events)-emitter.events_head > accumulate { - return false - } - var level int - for i := emitter.events_head; i < len(emitter.events); i++ { - switch emitter.events[i].typ { - case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: - level++ - case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: - level-- - } - if level == 0 { - return false - } - } - return true -} - -// Append a directive to the directives stack. -func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { - for i := 0; i < len(emitter.tag_directives); i++ { - if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") - } - } - - // [Go] Do we actually need to copy this given garbage collection - // and the lack of deallocating destructors? - tag_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(tag_copy.handle, value.handle) - copy(tag_copy.prefix, value.prefix) - emitter.tag_directives = append(emitter.tag_directives, tag_copy) - return true -} - -// Increase the indentation level. -func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { - emitter.indents = append(emitter.indents, emitter.indent) - if emitter.indent < 0 { - if flow { - emitter.indent = emitter.best_indent - } else { - emitter.indent = 0 - } - } else if !indentless { - emitter.indent += emitter.best_indent - } - return true -} - -// State dispatcher. -func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { - switch emitter.state { - default: - case yaml_EMIT_STREAM_START_STATE: - return yaml_emitter_emit_stream_start(emitter, event) - - case yaml_EMIT_FIRST_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, true) - - case yaml_EMIT_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, false) - - case yaml_EMIT_DOCUMENT_CONTENT_STATE: - return yaml_emitter_emit_document_content(emitter, event) - - case yaml_EMIT_DOCUMENT_END_STATE: - return yaml_emitter_emit_document_end(emitter, event) - - case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, true) - - case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, false) - - case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, true) - - case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, false) - - case yaml_EMIT_END_STATE: - return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") - } - panic("invalid emitter state") -} - -// Expect STREAM-START. -func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_STREAM_START_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") - } - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = event.encoding - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = yaml_UTF8_ENCODING - } - } - if emitter.best_indent < 2 || emitter.best_indent > 9 { - emitter.best_indent = 2 - } - if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { - emitter.best_width = 80 - } - if emitter.best_width < 0 { - emitter.best_width = 1<<31 - 1 - } - if emitter.line_break == yaml_ANY_BREAK { - emitter.line_break = yaml_LN_BREAK - } - - emitter.indent = -1 - emitter.line = 0 - emitter.column = 0 - emitter.whitespace = true - emitter.indention = true - - if emitter.encoding != yaml_UTF8_ENCODING { - if !yaml_emitter_write_bom(emitter) { - return false - } - } - emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE - return true -} - -// Expect DOCUMENT-START or STREAM-END. -func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - - if event.typ == yaml_DOCUMENT_START_EVENT { - - if event.version_directive != nil { - if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { - return false - } - } - - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { - return false - } - if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { - return false - } - } - - for i := 0; i < len(default_tag_directives); i++ { - tag_directive := &default_tag_directives[i] - if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { - return false - } - } - - implicit := event.implicit - if !first || emitter.canonical { - implicit = false - } - - if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if event.version_directive != nil { - implicit = false - if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if len(event.tag_directives) > 0 { - implicit = false - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { - return false - } - if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - if yaml_emitter_check_empty_document(emitter) { - implicit = false - } - if !implicit { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { - return false - } - if emitter.canonical { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE - return true - } - - if event.typ == yaml_STREAM_END_EVENT { - if emitter.open_ended { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_END_STATE - return true - } - - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") -} - -// Expect the root node. -func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) - return yaml_emitter_emit_node(emitter, event, true, false, false, false) -} - -// Expect DOCUMENT-END. -func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_DOCUMENT_END_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !event.implicit { - // [Go] Allocate the slice elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_DOCUMENT_START_STATE - emitter.tag_directives = emitter.tag_directives[:0] - return true -} - -// Expect a flow item node. -func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a flow key node. -func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_MAPPING_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a flow value node. -func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block item node. -func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) { - return false - } - } - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a block key node. -func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, false) { - return false - } - } - if event.typ == yaml_MAPPING_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block value node. -func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a node. -func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, - root bool, sequence bool, mapping bool, simple_key bool) bool { - - emitter.root_context = root - emitter.sequence_context = sequence - emitter.mapping_context = mapping - emitter.simple_key_context = simple_key - - switch event.typ { - case yaml_ALIAS_EVENT: - return yaml_emitter_emit_alias(emitter, event) - case yaml_SCALAR_EVENT: - return yaml_emitter_emit_scalar(emitter, event) - case yaml_SEQUENCE_START_EVENT: - return yaml_emitter_emit_sequence_start(emitter, event) - case yaml_MAPPING_START_EVENT: - return yaml_emitter_emit_mapping_start(emitter, event) - default: - return yaml_emitter_set_emitter_error(emitter, - fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) - } -} - -// Expect ALIAS. -func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SCALAR. -func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_select_scalar_style(emitter, event) { - return false - } - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - if !yaml_emitter_process_scalar(emitter) { - return false - } - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SEQUENCE-START. -func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || - yaml_emitter_check_empty_sequence(emitter) { - emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE - } - return true -} - -// Expect MAPPING-START. -func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || - yaml_emitter_check_empty_mapping(emitter) { - emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE - } - return true -} - -// Check if the document content is an empty scalar. -func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { - return false // [Go] Huh? -} - -// Check if the next events represent an empty sequence. -func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT -} - -// Check if the next events represent an empty mapping. -func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT -} - -// Check if the next node can be expressed as a simple key. -func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { - length := 0 - switch emitter.events[emitter.events_head].typ { - case yaml_ALIAS_EVENT: - length += len(emitter.anchor_data.anchor) - case yaml_SCALAR_EVENT: - if emitter.scalar_data.multiline { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) + - len(emitter.scalar_data.value) - case yaml_SEQUENCE_START_EVENT: - if !yaml_emitter_check_empty_sequence(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - case yaml_MAPPING_START_EVENT: - if !yaml_emitter_check_empty_mapping(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - default: - return false - } - return length <= 128 -} - -// Determine an acceptable scalar style. -func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 - if no_tag && !event.implicit && !event.quoted_implicit { - return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") - } - - style := event.scalar_style() - if style == yaml_ANY_SCALAR_STYLE { - style = yaml_PLAIN_SCALAR_STYLE - } - if emitter.canonical { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - if emitter.simple_key_context && emitter.scalar_data.multiline { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - - if style == yaml_PLAIN_SCALAR_STYLE { - if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || - emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if no_tag && !event.implicit { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { - if !emitter.scalar_data.single_quoted_allowed { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { - if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - - if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { - emitter.tag_data.handle = []byte{'!'} - } - emitter.scalar_data.style = style - return true -} - -// Write an anchor. -func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { - if emitter.anchor_data.anchor == nil { - return true - } - c := []byte{'&'} - if emitter.anchor_data.alias { - c[0] = '*' - } - if !yaml_emitter_write_indicator(emitter, c, true, false, false) { - return false - } - return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) -} - -// Write a tag. -func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { - if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { - return true - } - if len(emitter.tag_data.handle) > 0 { - if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { - return false - } - if len(emitter.tag_data.suffix) > 0 { - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - } - } else { - // [Go] Allocate these slices elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { - return false - } - } - return true -} - -// Write a scalar. -func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { - switch emitter.scalar_data.style { - case yaml_PLAIN_SCALAR_STYLE: - return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_SINGLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_DOUBLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_LITERAL_SCALAR_STYLE: - return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) - - case yaml_FOLDED_SCALAR_STYLE: - return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) - } - panic("unknown scalar style") -} - -// Check if a %YAML directive is valid. -func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { - if version_directive.major != 1 || version_directive.minor != 1 { - return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") - } - return true -} - -// Check if a %TAG directive is valid. -func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { - handle := tag_directive.handle - prefix := tag_directive.prefix - if len(handle) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") - } - if handle[0] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") - } - if handle[len(handle)-1] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") - } - for i := 1; i < len(handle)-1; i += width(handle[i]) { - if !is_alpha(handle, i) { - return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") - } - } - if len(prefix) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") - } - return true -} - -// Check if an anchor is valid. -func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { - if len(anchor) == 0 { - problem := "anchor value must not be empty" - if alias { - problem = "alias value must not be empty" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - for i := 0; i < len(anchor); i += width(anchor[i]) { - if !is_alpha(anchor, i) { - problem := "anchor value must contain alphanumerical characters only" - if alias { - problem = "alias value must contain alphanumerical characters only" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - } - emitter.anchor_data.anchor = anchor - emitter.anchor_data.alias = alias - return true -} - -// Check if a tag is valid. -func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { - if len(tag) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") - } - for i := 0; i < len(emitter.tag_directives); i++ { - tag_directive := &emitter.tag_directives[i] - if bytes.HasPrefix(tag, tag_directive.prefix) { - emitter.tag_data.handle = tag_directive.handle - emitter.tag_data.suffix = tag[len(tag_directive.prefix):] - return true - } - } - emitter.tag_data.suffix = tag - return true -} - -// Check if a scalar is valid. -func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { - var ( - block_indicators = false - flow_indicators = false - line_breaks = false - special_characters = false - - leading_space = false - leading_break = false - trailing_space = false - trailing_break = false - break_space = false - space_break = false - - preceded_by_whitespace = false - followed_by_whitespace = false - previous_space = false - previous_break = false - ) - - emitter.scalar_data.value = value - - if len(value) == 0 { - emitter.scalar_data.multiline = false - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = false - return true - } - - if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { - block_indicators = true - flow_indicators = true - } - - preceded_by_whitespace = true - for i, w := 0, 0; i < len(value); i += w { - w = width(value[i]) - followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) - - if i == 0 { - switch value[i] { - case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': - flow_indicators = true - block_indicators = true - case '?', ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '-': - if followed_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } else { - switch value[i] { - case ',', '?', '[', ']', '{', '}': - flow_indicators = true - case ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '#': - if preceded_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } - - if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { - special_characters = true - } - if is_space(value, i) { - if i == 0 { - leading_space = true - } - if i+width(value[i]) == len(value) { - trailing_space = true - } - if previous_break { - break_space = true - } - previous_space = true - previous_break = false - } else if is_break(value, i) { - line_breaks = true - if i == 0 { - leading_break = true - } - if i+width(value[i]) == len(value) { - trailing_break = true - } - if previous_space { - space_break = true - } - previous_space = false - previous_break = true - } else { - previous_space = false - previous_break = false - } - - // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. - preceded_by_whitespace = is_blankz(value, i) - } - - emitter.scalar_data.multiline = line_breaks - emitter.scalar_data.flow_plain_allowed = true - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = true - - if leading_space || leading_break || trailing_space || trailing_break { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if trailing_space { - emitter.scalar_data.block_allowed = false - } - if break_space { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - } - if space_break || special_characters { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - emitter.scalar_data.block_allowed = false - } - if line_breaks { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if flow_indicators { - emitter.scalar_data.flow_plain_allowed = false - } - if block_indicators { - emitter.scalar_data.block_plain_allowed = false - } - return true -} - -// Check if the event data is valid. -func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - emitter.anchor_data.anchor = nil - emitter.tag_data.handle = nil - emitter.tag_data.suffix = nil - emitter.scalar_data.value = nil - - switch event.typ { - case yaml_ALIAS_EVENT: - if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { - return false - } - - case yaml_SCALAR_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - if !yaml_emitter_analyze_scalar(emitter, event.value) { - return false - } - - case yaml_SEQUENCE_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - - case yaml_MAPPING_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - } - return true -} - -// Write the BOM character. -func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { - if !flush(emitter) { - return false - } - pos := emitter.buffer_pos - emitter.buffer[pos+0] = '\xEF' - emitter.buffer[pos+1] = '\xBB' - emitter.buffer[pos+2] = '\xBF' - emitter.buffer_pos += 3 - return true -} - -func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { - indent := emitter.indent - if indent < 0 { - indent = 0 - } - if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { - if !put_break(emitter) { - return false - } - } - for emitter.column < indent { - if !put(emitter, ' ') { - return false - } - } - emitter.whitespace = true - emitter.indention = true - return true -} - -func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, indicator) { - return false - } - emitter.whitespace = is_whitespace - emitter.indention = (emitter.indention && is_indention) - emitter.open_ended = false - return true -} - -func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - for i := 0; i < len(value); { - var must_write bool - switch value[i] { - case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': - must_write = true - default: - must_write = is_alpha(value, i) - } - if must_write { - if !write(emitter, value, &i) { - return false - } - } else { - w := width(value[i]) - for k := 0; k < w; k++ { - octet := value[i] - i++ - if !put(emitter, '%') { - return false - } - - c := octet >> 4 - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - - c = octet & 0x0f - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - } - } - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - - emitter.whitespace = false - emitter.indention = false - if emitter.root_context { - emitter.open_ended = true - } - - return true -} - -func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { - return false - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if value[i] == '\'' { - if !put(emitter, '\'') { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - spaces := false - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { - return false - } - - for i := 0; i < len(value); { - if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || - is_bom(value, i) || is_break(value, i) || - value[i] == '"' || value[i] == '\\' { - - octet := value[i] - - var w int - var v rune - switch { - case octet&0x80 == 0x00: - w, v = 1, rune(octet&0x7F) - case octet&0xE0 == 0xC0: - w, v = 2, rune(octet&0x1F) - case octet&0xF0 == 0xE0: - w, v = 3, rune(octet&0x0F) - case octet&0xF8 == 0xF0: - w, v = 4, rune(octet&0x07) - } - for k := 1; k < w; k++ { - octet = value[i+k] - v = (v << 6) + (rune(octet) & 0x3F) - } - i += w - - if !put(emitter, '\\') { - return false - } - - var ok bool - switch v { - case 0x00: - ok = put(emitter, '0') - case 0x07: - ok = put(emitter, 'a') - case 0x08: - ok = put(emitter, 'b') - case 0x09: - ok = put(emitter, 't') - case 0x0A: - ok = put(emitter, 'n') - case 0x0b: - ok = put(emitter, 'v') - case 0x0c: - ok = put(emitter, 'f') - case 0x0d: - ok = put(emitter, 'r') - case 0x1b: - ok = put(emitter, 'e') - case 0x22: - ok = put(emitter, '"') - case 0x5c: - ok = put(emitter, '\\') - case 0x85: - ok = put(emitter, 'N') - case 0xA0: - ok = put(emitter, '_') - case 0x2028: - ok = put(emitter, 'L') - case 0x2029: - ok = put(emitter, 'P') - default: - if v <= 0xFF { - ok = put(emitter, 'x') - w = 2 - } else if v <= 0xFFFF { - ok = put(emitter, 'u') - w = 4 - } else { - ok = put(emitter, 'U') - w = 8 - } - for k := (w - 1) * 4; ok && k >= 0; k -= 4 { - digit := byte((v >> uint(k)) & 0x0F) - if digit < 10 { - ok = put(emitter, digit+'0') - } else { - ok = put(emitter, digit+'A'-10) - } - } - } - if !ok { - return false - } - spaces = false - } else if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { - if !yaml_emitter_write_indent(emitter) { - return false - } - if is_space(value, i+1) { - if !put(emitter, '\\') { - return false - } - } - i += width(value[i]) - } else if !write(emitter, value, &i) { - return false - } - spaces = true - } else { - if !write(emitter, value, &i) { - return false - } - spaces = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { - if is_space(value, 0) || is_break(value, 0) { - indent_hint := []byte{'0' + byte(emitter.best_indent)} - if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { - return false - } - } - - emitter.open_ended = false - - var chomp_hint [1]byte - if len(value) == 0 { - chomp_hint[0] = '-' - } else { - i := len(value) - 1 - for value[i]&0xC0 == 0x80 { - i-- - } - if !is_break(value, i) { - chomp_hint[0] = '-' - } else if i == 0 { - chomp_hint[0] = '+' - emitter.open_ended = true - } else { - i-- - for value[i]&0xC0 == 0x80 { - i-- - } - if is_break(value, i) { - chomp_hint[0] = '+' - emitter.open_ended = true - } - } - } - if chomp_hint[0] != 0 { - if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { - return false - } - } - return true -} - -func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - breaks := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - breaks = false - } - } - - return true -} - -func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - - breaks := true - leading_spaces := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !breaks && !leading_spaces && value[i] == '\n' { - k := 0 - for is_break(value, k) { - k += width(value[k]) - } - if !is_blankz(value, k) { - if !put_break(emitter) { - return false - } - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - leading_spaces = is_blank(value, i) - } - if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - emitter.indention = false - breaks = false - } - } - return true -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/encode.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/encode.go deleted file mode 100644 index 0ee738e11b..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/encode.go +++ /dev/null @@ -1,390 +0,0 @@ -package yaml - -import ( - "encoding" - "fmt" - "io" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -// jsonNumber is the interface of the encoding/json.Number datatype. -// Repeating the interface here avoids a dependency on encoding/json, and also -// supports other libraries like jsoniter, which use a similar datatype with -// the same interface. Detecting this interface is useful when dealing with -// structures containing json.Number, which is a string under the hood. The -// encoder should prefer the use of Int64(), Float64() and string(), in that -// order, when encoding this type. -type jsonNumber interface { - Float64() (float64, error) - Int64() (int64, error) - String() string -} - -type encoder struct { - emitter yaml_emitter_t - event yaml_event_t - out []byte - flow bool - // doneInit holds whether the initial stream_start_event has been - // emitted. - doneInit bool -} - -func newEncoder() *encoder { - e := &encoder{} - yaml_emitter_initialize(&e.emitter) - yaml_emitter_set_output_string(&e.emitter, &e.out) - yaml_emitter_set_unicode(&e.emitter, true) - return e -} - -func newEncoderWithWriter(w io.Writer) *encoder { - e := &encoder{} - yaml_emitter_initialize(&e.emitter) - yaml_emitter_set_output_writer(&e.emitter, w) - yaml_emitter_set_unicode(&e.emitter, true) - return e -} - -func (e *encoder) init() { - if e.doneInit { - return - } - yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) - e.emit() - e.doneInit = true -} - -func (e *encoder) finish() { - e.emitter.open_ended = false - yaml_stream_end_event_initialize(&e.event) - e.emit() -} - -func (e *encoder) destroy() { - yaml_emitter_delete(&e.emitter) -} - -func (e *encoder) emit() { - // This will internally delete the e.event value. - e.must(yaml_emitter_emit(&e.emitter, &e.event)) -} - -func (e *encoder) must(ok bool) { - if !ok { - msg := e.emitter.problem - if msg == "" { - msg = "unknown problem generating YAML content" - } - failf("%s", msg) - } -} - -func (e *encoder) marshalDoc(tag string, in reflect.Value) { - e.init() - yaml_document_start_event_initialize(&e.event, nil, nil, true) - e.emit() - e.marshal(tag, in) - yaml_document_end_event_initialize(&e.event, true) - e.emit() -} - -func (e *encoder) marshal(tag string, in reflect.Value) { - if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { - e.nilv() - return - } - iface := in.Interface() - switch m := iface.(type) { - case jsonNumber: - integer, err := m.Int64() - if err == nil { - // In this case the json.Number is a valid int64 - in = reflect.ValueOf(integer) - break - } - float, err := m.Float64() - if err == nil { - // In this case the json.Number is a valid float64 - in = reflect.ValueOf(float) - break - } - // fallback case - no number could be obtained - in = reflect.ValueOf(m.String()) - case time.Time, *time.Time: - // Although time.Time implements TextMarshaler, - // we don't want to treat it as a string for YAML - // purposes because YAML has special support for - // timestamps. - case Marshaler: - v, err := m.MarshalYAML() - if err != nil { - fail(err) - } - if v == nil { - e.nilv() - return - } - in = reflect.ValueOf(v) - case encoding.TextMarshaler: - text, err := m.MarshalText() - if err != nil { - fail(err) - } - in = reflect.ValueOf(string(text)) - case nil: - e.nilv() - return - } - switch in.Kind() { - case reflect.Interface: - e.marshal(tag, in.Elem()) - case reflect.Map: - e.mapv(tag, in) - case reflect.Ptr: - if in.Type() == ptrTimeType { - e.timev(tag, in.Elem()) - } else { - e.marshal(tag, in.Elem()) - } - case reflect.Struct: - if in.Type() == timeType { - e.timev(tag, in) - } else { - e.structv(tag, in) - } - case reflect.Slice, reflect.Array: - if in.Type().Elem() == mapItemType { - e.itemsv(tag, in) - } else { - e.slicev(tag, in) - } - case reflect.String: - e.stringv(tag, in) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if in.Type() == durationType { - e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) - } else { - e.intv(tag, in) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - e.uintv(tag, in) - case reflect.Float32, reflect.Float64: - e.floatv(tag, in) - case reflect.Bool: - e.boolv(tag, in) - default: - panic("cannot marshal type: " + in.Type().String()) - } -} - -func (e *encoder) mapv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - keys := keyList(in.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - e.marshal("", k) - e.marshal("", in.MapIndex(k)) - } - }) -} - -func (e *encoder) itemsv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) - for _, item := range slice { - e.marshal("", reflect.ValueOf(item.Key)) - e.marshal("", reflect.ValueOf(item.Value)) - } - }) -} - -func (e *encoder) structv(tag string, in reflect.Value) { - sinfo, err := getStructInfo(in.Type()) - if err != nil { - panic(err) - } - e.mappingv(tag, func() { - for _, info := range sinfo.FieldsList { - var value reflect.Value - if info.Inline == nil { - value = in.Field(info.Num) - } else { - value = in.FieldByIndex(info.Inline) - } - if info.OmitEmpty && isZero(value) { - continue - } - e.marshal("", reflect.ValueOf(info.Key)) - e.flow = info.Flow - e.marshal("", value) - } - if sinfo.InlineMap >= 0 { - m := in.Field(sinfo.InlineMap) - if m.Len() > 0 { - e.flow = false - keys := keyList(m.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - if _, found := sinfo.FieldsMap[k.String()]; found { - panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) - } - e.marshal("", k) - e.flow = false - e.marshal("", m.MapIndex(k)) - } - } - } - }) -} - -func (e *encoder) mappingv(tag string, f func()) { - implicit := tag == "" - style := yaml_BLOCK_MAPPING_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_MAPPING_STYLE - } - yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) - e.emit() - f() - yaml_mapping_end_event_initialize(&e.event) - e.emit() -} - -func (e *encoder) slicev(tag string, in reflect.Value) { - implicit := tag == "" - style := yaml_BLOCK_SEQUENCE_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_SEQUENCE_STYLE - } - e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) - e.emit() - n := in.Len() - for i := 0; i < n; i++ { - e.marshal("", in.Index(i)) - } - e.must(yaml_sequence_end_event_initialize(&e.event)) - e.emit() -} - -// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. -// -// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported -// in YAML 1.2 and by this package, but these should be marshalled quoted for -// the time being for compatibility with other parsers. -func isBase60Float(s string) (result bool) { - // Fast path. - if s == "" { - return false - } - c := s[0] - if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { - return false - } - // Do the full match. - return base60float.MatchString(s) -} - -// From http://yaml.org/type/float.html, except the regular expression there -// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. -var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) - -func (e *encoder) stringv(tag string, in reflect.Value) { - var style yaml_scalar_style_t - s := in.String() - canUsePlain := true - switch { - case !utf8.ValidString(s): - if tag == yaml_BINARY_TAG { - failf("explicitly tagged !!binary data must be base64-encoded") - } - if tag != "" { - failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) - } - // It can't be encoded directly as YAML so use a binary tag - // and encode it as base64. - tag = yaml_BINARY_TAG - s = encodeBase64(s) - case tag == "": - // Check to see if it would resolve to a specific - // tag when encoded unquoted. If it doesn't, - // there's no need to quote it. - rtag, _ := resolve("", s) - canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s) - } - // Note: it's possible for user code to emit invalid YAML - // if they explicitly specify a tag and a string containing - // text that's incompatible with that tag. - switch { - case strings.Contains(s, "\n"): - style = yaml_LITERAL_SCALAR_STYLE - case canUsePlain: - style = yaml_PLAIN_SCALAR_STYLE - default: - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - e.emitScalar(s, "", tag, style) -} - -func (e *encoder) boolv(tag string, in reflect.Value) { - var s string - if in.Bool() { - s = "true" - } else { - s = "false" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) intv(tag string, in reflect.Value) { - s := strconv.FormatInt(in.Int(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) uintv(tag string, in reflect.Value) { - s := strconv.FormatUint(in.Uint(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) timev(tag string, in reflect.Value) { - t := in.Interface().(time.Time) - s := t.Format(time.RFC3339Nano) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) floatv(tag string, in reflect.Value) { - // Issue #352: When formatting, use the precision of the underlying value - precision := 64 - if in.Kind() == reflect.Float32 { - precision = 32 - } - - s := strconv.FormatFloat(in.Float(), 'g', -1, precision) - switch s { - case "+Inf": - s = ".inf" - case "-Inf": - s = "-.inf" - case "NaN": - s = ".nan" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) nilv() { - e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { - implicit := tag == "" - e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) - e.emit() -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/parserc.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/parserc.go deleted file mode 100644 index 81d05dfe57..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/parserc.go +++ /dev/null @@ -1,1095 +0,0 @@ -package yaml - -import ( - "bytes" -) - -// The parser implements the following grammar: -// -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// implicit_document ::= block_node DOCUMENT-END* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// block_node_or_indentless_sequence ::= -// ALIAS -// | properties (block_content | indentless_block_sequence)? -// | block_content -// | indentless_block_sequence -// block_node ::= ALIAS -// | properties block_content? -// | block_content -// flow_node ::= ALIAS -// | properties flow_content? -// | flow_content -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// block_content ::= block_collection | flow_collection | SCALAR -// flow_content ::= flow_collection | SCALAR -// block_collection ::= block_sequence | block_mapping -// flow_collection ::= flow_sequence | flow_mapping -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// block_mapping ::= BLOCK-MAPPING_START -// ((KEY block_node_or_indentless_sequence?)? -// (VALUE block_node_or_indentless_sequence?)?)* -// BLOCK-END -// flow_sequence ::= FLOW-SEQUENCE-START -// (flow_sequence_entry FLOW-ENTRY)* -// flow_sequence_entry? -// FLOW-SEQUENCE-END -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// flow_mapping ::= FLOW-MAPPING-START -// (flow_mapping_entry FLOW-ENTRY)* -// flow_mapping_entry? -// FLOW-MAPPING-END -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - -// Peek the next token in the token queue. -func peek_token(parser *yaml_parser_t) *yaml_token_t { - if parser.token_available || yaml_parser_fetch_more_tokens(parser) { - return &parser.tokens[parser.tokens_head] - } - return nil -} - -// Remove the next token from the queue (must be called after peek_token). -func skip_token(parser *yaml_parser_t) { - parser.token_available = false - parser.tokens_parsed++ - parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN - parser.tokens_head++ -} - -// Get the next event. -func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { - // Erase the event object. - *event = yaml_event_t{} - - // No events after the end of the stream or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { - return true - } - - // Generate the next event. - return yaml_parser_state_machine(parser, event) -} - -// Set parser error. -func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -// State dispatcher. -func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { - //trace("yaml_parser_state_machine", "state:", parser.state.String()) - - switch parser.state { - case yaml_PARSE_STREAM_START_STATE: - return yaml_parser_parse_stream_start(parser, event) - - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, true) - - case yaml_PARSE_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, false) - - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return yaml_parser_parse_document_content(parser, event) - - case yaml_PARSE_DOCUMENT_END_STATE: - return yaml_parser_parse_document_end(parser, event) - - case yaml_PARSE_BLOCK_NODE_STATE: - return yaml_parser_parse_node(parser, event, true, false) - - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return yaml_parser_parse_node(parser, event, true, true) - - case yaml_PARSE_FLOW_NODE_STATE: - return yaml_parser_parse_node(parser, event, false, false) - - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, true) - - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, false) - - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_indentless_sequence_entry(parser, event) - - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, true) - - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, false) - - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return yaml_parser_parse_block_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, true) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, false) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) - - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, true) - - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, true) - - default: - panic("invalid parser state") - } -} - -// Parse the production: -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// ************ -func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_STREAM_START_TOKEN { - return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) - } - parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - encoding: token.encoding, - } - skip_token(parser) - return true -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// * -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// ************************* -func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { - - token := peek_token(parser) - if token == nil { - return false - } - - // Parse extra document end indicators. - if !implicit { - for token.typ == yaml_DOCUMENT_END_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && - token.typ != yaml_TAG_DIRECTIVE_TOKEN && - token.typ != yaml_DOCUMENT_START_TOKEN && - token.typ != yaml_STREAM_END_TOKEN { - // Parse an implicit document. - if !yaml_parser_process_directives(parser, nil, nil) { - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_BLOCK_NODE_STATE - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - } else if token.typ != yaml_STREAM_END_TOKEN { - // Parse an explicit document. - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - start_mark := token.start_mark - if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { - return false - } - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_DOCUMENT_START_TOKEN { - yaml_parser_set_parser_error(parser, - "did not find expected ", token.start_mark) - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE - end_mark := token.end_mark - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: false, - } - skip_token(parser) - - } else { - // Parse the stream end. - parser.state = yaml_PARSE_END_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - } - - return true -} - -// Parse the productions: -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// *********** -// -func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || - token.typ == yaml_TAG_DIRECTIVE_TOKEN || - token.typ == yaml_DOCUMENT_START_TOKEN || - token.typ == yaml_DOCUMENT_END_TOKEN || - token.typ == yaml_STREAM_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - return yaml_parser_process_empty_scalar(parser, event, - token.start_mark) - } - return yaml_parser_parse_node(parser, event, true, false) -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// ************* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// -func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - start_mark := token.start_mark - end_mark := token.start_mark - - implicit := true - if token.typ == yaml_DOCUMENT_END_TOKEN { - end_mark = token.end_mark - skip_token(parser) - implicit = false - } - - parser.tag_directives = parser.tag_directives[:0] - - parser.state = yaml_PARSE_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - start_mark: start_mark, - end_mark: end_mark, - implicit: implicit, - } - return true -} - -// Parse the productions: -// block_node_or_indentless_sequence ::= -// ALIAS -// ***** -// | properties (block_content | indentless_block_sequence)? -// ********** * -// | block_content | indentless_block_sequence -// * -// block_node ::= ALIAS -// ***** -// | properties block_content? -// ********** * -// | block_content -// * -// flow_node ::= ALIAS -// ***** -// | properties flow_content? -// ********** * -// | flow_content -// * -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// ************************* -// block_content ::= block_collection | flow_collection | SCALAR -// ****** -// flow_content ::= flow_collection | SCALAR -// ****** -func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { - //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_ALIAS_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - *event = yaml_event_t{ - typ: yaml_ALIAS_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - anchor: token.value, - } - skip_token(parser) - return true - } - - start_mark := token.start_mark - end_mark := token.start_mark - - var tag_token bool - var tag_handle, tag_suffix, anchor []byte - var tag_mark yaml_mark_t - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - start_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } else if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - start_mark = token.start_mark - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - var tag []byte - if tag_token { - if len(tag_handle) == 0 { - tag = tag_suffix - tag_suffix = nil - } else { - for i := range parser.tag_directives { - if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { - tag = append([]byte(nil), parser.tag_directives[i].prefix...) - tag = append(tag, tag_suffix...) - break - } - } - if len(tag) == 0 { - yaml_parser_set_parser_error_context(parser, - "while parsing a node", start_mark, - "found undefined tag handle", tag_mark) - return false - } - } - } - - implicit := len(tag) == 0 - if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_SCALAR_TOKEN { - var plain_implicit, quoted_implicit bool - end_mark = token.end_mark - if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { - plain_implicit = true - } else if len(tag) == 0 { - quoted_implicit = true - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - value: token.value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(token.style), - } - skip_token(parser) - return true - } - if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { - // [Go] Some of the events below can be merged as they differ only on style. - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_FLOW_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), - } - return true - } - if len(anchor) > 0 || len(tag) > 0 { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - quoted_implicit: false, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true - } - - context := "while parsing a flow node" - if block { - context = "while parsing a block node" - } - yaml_parser_set_parser_error_context(parser, context, start_mark, - "did not find expected node content", token.start_mark) - return false -} - -// Parse the productions: -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// ******************** *********** * ********* -// -func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } else { - parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } - if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block collection", context_mark, - "did not find expected '-' indicator", token.start_mark) -} - -// Parse the productions: -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// *********** * -func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && - token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? - } - return true -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// ******************* -// ((KEY block_node_or_indentless_sequence?)? -// *** * -// (VALUE block_node_or_indentless_sequence?)?)* -// -// BLOCK-END -// ********* -// -func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_KEY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } else { - parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } else if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block mapping", context_mark, - "did not find expected key", token.start_mark) -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// -// ((KEY block_node_or_indentless_sequence?)? -// -// (VALUE block_node_or_indentless_sequence?)?)* -// ***** * -// BLOCK-END -// -// -func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence ::= FLOW-SEQUENCE-START -// ******************* -// (flow_sequence_entry FLOW-ENTRY)* -// * ********** -// flow_sequence_entry? -// * -// FLOW-SEQUENCE-END -// ***************** -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow sequence", context_mark, - "did not find expected ',' or ']'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - implicit: true, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - skip_token(parser) - return true - } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true -} - -// -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// *** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - mark := token.end_mark - skip_token(parser) - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// ***** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? - } - return true -} - -// Parse the productions: -// flow_mapping ::= FLOW-MAPPING-START -// ****************** -// (flow_mapping_entry FLOW-ENTRY)* -// * ********** -// flow_mapping_entry? -// ****************** -// FLOW-MAPPING-END -// **************** -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * *** * -// -func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow mapping", context_mark, - "did not find expected ',' or '}'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } else { - parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true -} - -// Parse the productions: -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * ***** * -// -func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { - token := peek_token(parser) - if token == nil { - return false - } - if empty { - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Generate an empty scalar event. -func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: mark, - end_mark: mark, - value: nil, // Empty - implicit: true, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true -} - -var default_tag_directives = []yaml_tag_directive_t{ - {[]byte("!"), []byte("!")}, - {[]byte("!!"), []byte("tag:yaml.org,2002:")}, -} - -// Parse directives. -func yaml_parser_process_directives(parser *yaml_parser_t, - version_directive_ref **yaml_version_directive_t, - tag_directives_ref *[]yaml_tag_directive_t) bool { - - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - - token := peek_token(parser) - if token == nil { - return false - } - - for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { - if version_directive != nil { - yaml_parser_set_parser_error(parser, - "found duplicate %YAML directive", token.start_mark) - return false - } - if token.major != 1 || token.minor != 1 { - yaml_parser_set_parser_error(parser, - "found incompatible YAML document", token.start_mark) - return false - } - version_directive = &yaml_version_directive_t{ - major: token.major, - minor: token.minor, - } - } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { - value := yaml_tag_directive_t{ - handle: token.value, - prefix: token.prefix, - } - if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { - return false - } - tag_directives = append(tag_directives, value) - } - - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - - for i := range default_tag_directives { - if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { - return false - } - } - - if version_directive_ref != nil { - *version_directive_ref = version_directive - } - if tag_directives_ref != nil { - *tag_directives_ref = tag_directives - } - return true -} - -// Append a tag directive to the directives stack. -func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { - for i := range parser.tag_directives { - if bytes.Equal(value.handle, parser.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) - } - } - - // [Go] I suspect the copy is unnecessary. This was likely done - // because there was no way to track ownership of the data. - value_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(value_copy.handle, value.handle) - copy(value_copy.prefix, value.prefix) - parser.tag_directives = append(parser.tag_directives, value_copy) - return true -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/readerc.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/readerc.go deleted file mode 100644 index 7c1f5fac3d..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/readerc.go +++ /dev/null @@ -1,412 +0,0 @@ -package yaml - -import ( - "io" -) - -// Set the reader error and return 0. -func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { - parser.error = yaml_READER_ERROR - parser.problem = problem - parser.problem_offset = offset - parser.problem_value = value - return false -} - -// Byte order marks. -const ( - bom_UTF8 = "\xef\xbb\xbf" - bom_UTF16LE = "\xff\xfe" - bom_UTF16BE = "\xfe\xff" -) - -// Determine the input stream encoding by checking the BOM symbol. If no BOM is -// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. -func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { - // Ensure that we had enough bytes in the raw buffer. - for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { - if !yaml_parser_update_raw_buffer(parser) { - return false - } - } - - // Determine the encoding. - buf := parser.raw_buffer - pos := parser.raw_buffer_pos - avail := len(buf) - pos - if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { - parser.encoding = yaml_UTF16LE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { - parser.encoding = yaml_UTF16BE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { - parser.encoding = yaml_UTF8_ENCODING - parser.raw_buffer_pos += 3 - parser.offset += 3 - } else { - parser.encoding = yaml_UTF8_ENCODING - } - return true -} - -// Update the raw buffer. -func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { - size_read := 0 - - // Return if the raw buffer is full. - if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { - return true - } - - // Return on EOF. - if parser.eof { - return true - } - - // Move the remaining bytes in the raw buffer to the beginning. - if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { - copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) - } - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] - parser.raw_buffer_pos = 0 - - // Call the read handler to fill the buffer. - size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] - if err == io.EOF { - parser.eof = true - } else if err != nil { - return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) - } - return true -} - -// Ensure that the buffer contains at least `length` characters. -// Return true on success, false on failure. -// -// The length is supposed to be significantly less that the buffer size. -func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { - if parser.read_handler == nil { - panic("read handler must be set") - } - - // [Go] This function was changed to guarantee the requested length size at EOF. - // The fact we need to do this is pretty awful, but the description above implies - // for that to be the case, and there are tests - - // If the EOF flag is set and the raw buffer is empty, do nothing. - if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { - // [Go] ACTUALLY! Read the documentation of this function above. - // This is just broken. To return true, we need to have the - // given length in the buffer. Not doing that means every single - // check that calls this function to make sure the buffer has a - // given length is Go) panicking; or C) accessing invalid memory. - //return true - } - - // Return if the buffer contains enough characters. - if parser.unread >= length { - return true - } - - // Determine the input encoding if it is not known yet. - if parser.encoding == yaml_ANY_ENCODING { - if !yaml_parser_determine_encoding(parser) { - return false - } - } - - // Move the unread characters to the beginning of the buffer. - buffer_len := len(parser.buffer) - if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { - copy(parser.buffer, parser.buffer[parser.buffer_pos:]) - buffer_len -= parser.buffer_pos - parser.buffer_pos = 0 - } else if parser.buffer_pos == buffer_len { - buffer_len = 0 - parser.buffer_pos = 0 - } - - // Open the whole buffer for writing, and cut it before returning. - parser.buffer = parser.buffer[:cap(parser.buffer)] - - // Fill the buffer until it has enough characters. - first := true - for parser.unread < length { - - // Fill the raw buffer if necessary. - if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { - if !yaml_parser_update_raw_buffer(parser) { - parser.buffer = parser.buffer[:buffer_len] - return false - } - } - first = false - - // Decode the raw buffer. - inner: - for parser.raw_buffer_pos != len(parser.raw_buffer) { - var value rune - var width int - - raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos - - // Decode the next character. - switch parser.encoding { - case yaml_UTF8_ENCODING: - // Decode a UTF-8 character. Check RFC 3629 - // (http://www.ietf.org/rfc/rfc3629.txt) for more details. - // - // The following table (taken from the RFC) is used for - // decoding. - // - // Char. number range | UTF-8 octet sequence - // (hexadecimal) | (binary) - // --------------------+------------------------------------ - // 0000 0000-0000 007F | 0xxxxxxx - // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // - // Additionally, the characters in the range 0xD800-0xDFFF - // are prohibited as they are reserved for use with UTF-16 - // surrogate pairs. - - // Determine the length of the UTF-8 sequence. - octet := parser.raw_buffer[parser.raw_buffer_pos] - switch { - case octet&0x80 == 0x00: - width = 1 - case octet&0xE0 == 0xC0: - width = 2 - case octet&0xF0 == 0xE0: - width = 3 - case octet&0xF8 == 0xF0: - width = 4 - default: - // The leading octet is invalid. - return yaml_parser_set_reader_error(parser, - "invalid leading UTF-8 octet", - parser.offset, int(octet)) - } - - // Check if the raw buffer contains an incomplete character. - if width > raw_unread { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-8 octet sequence", - parser.offset, -1) - } - break inner - } - - // Decode the leading octet. - switch { - case octet&0x80 == 0x00: - value = rune(octet & 0x7F) - case octet&0xE0 == 0xC0: - value = rune(octet & 0x1F) - case octet&0xF0 == 0xE0: - value = rune(octet & 0x0F) - case octet&0xF8 == 0xF0: - value = rune(octet & 0x07) - default: - value = 0 - } - - // Check and decode the trailing octets. - for k := 1; k < width; k++ { - octet = parser.raw_buffer[parser.raw_buffer_pos+k] - - // Check if the octet is valid. - if (octet & 0xC0) != 0x80 { - return yaml_parser_set_reader_error(parser, - "invalid trailing UTF-8 octet", - parser.offset+k, int(octet)) - } - - // Decode the octet. - value = (value << 6) + rune(octet&0x3F) - } - - // Check the length of the sequence against the value. - switch { - case width == 1: - case width == 2 && value >= 0x80: - case width == 3 && value >= 0x800: - case width == 4 && value >= 0x10000: - default: - return yaml_parser_set_reader_error(parser, - "invalid length of a UTF-8 sequence", - parser.offset, -1) - } - - // Check the range of the value. - if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { - return yaml_parser_set_reader_error(parser, - "invalid Unicode character", - parser.offset, int(value)) - } - - case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: - var low, high int - if parser.encoding == yaml_UTF16LE_ENCODING { - low, high = 0, 1 - } else { - low, high = 1, 0 - } - - // The UTF-16 encoding is not as simple as one might - // naively think. Check RFC 2781 - // (http://www.ietf.org/rfc/rfc2781.txt). - // - // Normally, two subsequent bytes describe a Unicode - // character. However a special technique (called a - // surrogate pair) is used for specifying character - // values larger than 0xFFFF. - // - // A surrogate pair consists of two pseudo-characters: - // high surrogate area (0xD800-0xDBFF) - // low surrogate area (0xDC00-0xDFFF) - // - // The following formulas are used for decoding - // and encoding characters using surrogate pairs: - // - // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) - // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) - // W1 = 110110yyyyyyyyyy - // W2 = 110111xxxxxxxxxx - // - // where U is the character value, W1 is the high surrogate - // area, W2 is the low surrogate area. - - // Check for incomplete UTF-16 character. - if raw_unread < 2 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 character", - parser.offset, -1) - } - break inner - } - - // Get the character. - value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) - - // Check for unexpected low surrogate area. - if value&0xFC00 == 0xDC00 { - return yaml_parser_set_reader_error(parser, - "unexpected low surrogate area", - parser.offset, int(value)) - } - - // Check for a high surrogate area. - if value&0xFC00 == 0xD800 { - width = 4 - - // Check for incomplete surrogate pair. - if raw_unread < 4 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 surrogate pair", - parser.offset, -1) - } - break inner - } - - // Get the next character. - value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) - - // Check for a low surrogate area. - if value2&0xFC00 != 0xDC00 { - return yaml_parser_set_reader_error(parser, - "expected low surrogate area", - parser.offset+2, int(value2)) - } - - // Generate the value of the surrogate pair. - value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) - } else { - width = 2 - } - - default: - panic("impossible") - } - - // Check if the character is in the allowed range: - // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) - // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) - // | [#x10000-#x10FFFF] (32 bit) - switch { - case value == 0x09: - case value == 0x0A: - case value == 0x0D: - case value >= 0x20 && value <= 0x7E: - case value == 0x85: - case value >= 0xA0 && value <= 0xD7FF: - case value >= 0xE000 && value <= 0xFFFD: - case value >= 0x10000 && value <= 0x10FFFF: - default: - return yaml_parser_set_reader_error(parser, - "control characters are not allowed", - parser.offset, int(value)) - } - - // Move the raw pointers. - parser.raw_buffer_pos += width - parser.offset += width - - // Finally put the character into the buffer. - if value <= 0x7F { - // 0000 0000-0000 007F . 0xxxxxxx - parser.buffer[buffer_len+0] = byte(value) - buffer_len += 1 - } else if value <= 0x7FF { - // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) - parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) - buffer_len += 2 - } else if value <= 0xFFFF { - // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) - buffer_len += 3 - } else { - // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) - buffer_len += 4 - } - - parser.unread++ - } - - // On EOF, put NUL into the buffer and return. - if parser.eof { - parser.buffer[buffer_len] = 0 - buffer_len++ - parser.unread++ - break - } - } - // [Go] Read the documentation of this function above. To return true, - // we need to have the given length in the buffer. Not doing that means - // every single check that calls this function to make sure the buffer - // has a given length is Go) panicking; or C) accessing invalid memory. - // This happens here due to the EOF above breaking early. - for buffer_len < length { - parser.buffer[buffer_len] = 0 - buffer_len++ - } - parser.buffer = parser.buffer[:buffer_len] - return true -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/resolve.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/resolve.go deleted file mode 100644 index 4120e0c916..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/resolve.go +++ /dev/null @@ -1,258 +0,0 @@ -package yaml - -import ( - "encoding/base64" - "math" - "regexp" - "strconv" - "strings" - "time" -) - -type resolveMapItem struct { - value interface{} - tag string -} - -var resolveTable = make([]byte, 256) -var resolveMap = make(map[string]resolveMapItem) - -func init() { - t := resolveTable - t[int('+')] = 'S' // Sign - t[int('-')] = 'S' - for _, c := range "0123456789" { - t[int(c)] = 'D' // Digit - } - for _, c := range "yYnNtTfFoO~" { - t[int(c)] = 'M' // In map - } - t[int('.')] = '.' // Float (potentially in map) - - var resolveMapList = []struct { - v interface{} - tag string - l []string - }{ - {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, - {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, - {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, - {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, - {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, - {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, - {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, - {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, - {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, - {"<<", yaml_MERGE_TAG, []string{"<<"}}, - } - - m := resolveMap - for _, item := range resolveMapList { - for _, s := range item.l { - m[s] = resolveMapItem{item.v, item.tag} - } - } -} - -const longTagPrefix = "tag:yaml.org,2002:" - -func shortTag(tag string) string { - // TODO This can easily be made faster and produce less garbage. - if strings.HasPrefix(tag, longTagPrefix) { - return "!!" + tag[len(longTagPrefix):] - } - return tag -} - -func longTag(tag string) string { - if strings.HasPrefix(tag, "!!") { - return longTagPrefix + tag[2:] - } - return tag -} - -func resolvableTag(tag string) bool { - switch tag { - case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: - return true - } - return false -} - -var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`) - -func resolve(tag string, in string) (rtag string, out interface{}) { - if !resolvableTag(tag) { - return tag, in - } - - defer func() { - switch tag { - case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: - return - case yaml_FLOAT_TAG: - if rtag == yaml_INT_TAG { - switch v := out.(type) { - case int64: - rtag = yaml_FLOAT_TAG - out = float64(v) - return - case int: - rtag = yaml_FLOAT_TAG - out = float64(v) - return - } - } - } - failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) - }() - - // Any data is accepted as a !!str or !!binary. - // Otherwise, the prefix is enough of a hint about what it might be. - hint := byte('N') - if in != "" { - hint = resolveTable[in[0]] - } - if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { - // Handle things we can lookup in a map. - if item, ok := resolveMap[in]; ok { - return item.tag, item.value - } - - // Base 60 floats are a bad idea, were dropped in YAML 1.2, and - // are purposefully unsupported here. They're still quoted on - // the way out for compatibility with other parser, though. - - switch hint { - case 'M': - // We've already checked the map above. - - case '.': - // Not in the map, so maybe a normal float. - floatv, err := strconv.ParseFloat(in, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - - case 'D', 'S': - // Int, float, or timestamp. - // Only try values as a timestamp if the value is unquoted or there's an explicit - // !!timestamp tag. - if tag == "" || tag == yaml_TIMESTAMP_TAG { - t, ok := parseTimestamp(in) - if ok { - return yaml_TIMESTAMP_TAG, t - } - } - - plain := strings.Replace(in, "_", "", -1) - intv, err := strconv.ParseInt(plain, 0, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain, 0, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - if yamlStyleFloat.MatchString(plain) { - floatv, err := strconv.ParseFloat(plain, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - } - if strings.HasPrefix(plain, "0b") { - intv, err := strconv.ParseInt(plain[2:], 2, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain[2:], 2, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - } else if strings.HasPrefix(plain, "-0b") { - intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) - if err == nil { - if true || intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - } - default: - panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") - } - } - return yaml_STR_TAG, in -} - -// encodeBase64 encodes s as base64 that is broken up into multiple lines -// as appropriate for the resulting length. -func encodeBase64(s string) string { - const lineLen = 70 - encLen := base64.StdEncoding.EncodedLen(len(s)) - lines := encLen/lineLen + 1 - buf := make([]byte, encLen*2+lines) - in := buf[0:encLen] - out := buf[encLen:] - base64.StdEncoding.Encode(in, []byte(s)) - k := 0 - for i := 0; i < len(in); i += lineLen { - j := i + lineLen - if j > len(in) { - j = len(in) - } - k += copy(out[k:], in[i:j]) - if lines > 1 { - out[k] = '\n' - k++ - } - } - return string(out[:k]) -} - -// This is a subset of the formats allowed by the regular expression -// defined at http://yaml.org/type/timestamp.html. -var allowedTimestampFormats = []string{ - "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. - "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". - "2006-1-2 15:4:5.999999999", // space separated with no time zone - "2006-1-2", // date only - // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" - // from the set of examples. -} - -// parseTimestamp parses s as a timestamp string and -// returns the timestamp and reports whether it succeeded. -// Timestamp formats are defined at http://yaml.org/type/timestamp.html -func parseTimestamp(s string) (time.Time, bool) { - // TODO write code to check all the formats supported by - // http://yaml.org/type/timestamp.html instead of using time.Parse. - - // Quick check: all date formats start with YYYY-. - i := 0 - for ; i < len(s); i++ { - if c := s[i]; c < '0' || c > '9' { - break - } - } - if i != 4 || i == len(s) || s[i] != '-' { - return time.Time{}, false - } - for _, format := range allowedTimestampFormats { - if t, err := time.Parse(format, s); err == nil { - return t, true - } - } - return time.Time{}, false -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/scannerc.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/scannerc.go deleted file mode 100644 index 0b9bb6030a..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/scannerc.go +++ /dev/null @@ -1,2711 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Introduction -// ************ -// -// The following notes assume that you are familiar with the YAML specification -// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in -// some cases we are less restrictive that it requires. -// -// The process of transforming a YAML stream into a sequence of events is -// divided on two steps: Scanning and Parsing. -// -// The Scanner transforms the input stream into a sequence of tokens, while the -// parser transform the sequence of tokens produced by the Scanner into a -// sequence of parsing events. -// -// The Scanner is rather clever and complicated. The Parser, on the contrary, -// is a straightforward implementation of a recursive-descendant parser (or, -// LL(1) parser, as it is usually called). -// -// Actually there are two issues of Scanning that might be called "clever", the -// rest is quite straightforward. The issues are "block collection start" and -// "simple keys". Both issues are explained below in details. -// -// Here the Scanning step is explained and implemented. We start with the list -// of all the tokens produced by the Scanner together with short descriptions. -// -// Now, tokens: -// -// STREAM-START(encoding) # The stream start. -// STREAM-END # The stream end. -// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. -// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. -// DOCUMENT-START # '---' -// DOCUMENT-END # '...' -// BLOCK-SEQUENCE-START # Indentation increase denoting a block -// BLOCK-MAPPING-START # sequence or a block mapping. -// BLOCK-END # Indentation decrease. -// FLOW-SEQUENCE-START # '[' -// FLOW-SEQUENCE-END # ']' -// BLOCK-SEQUENCE-START # '{' -// BLOCK-SEQUENCE-END # '}' -// BLOCK-ENTRY # '-' -// FLOW-ENTRY # ',' -// KEY # '?' or nothing (simple keys). -// VALUE # ':' -// ALIAS(anchor) # '*anchor' -// ANCHOR(anchor) # '&anchor' -// TAG(handle,suffix) # '!handle!suffix' -// SCALAR(value,style) # A scalar. -// -// The following two tokens are "virtual" tokens denoting the beginning and the -// end of the stream: -// -// STREAM-START(encoding) -// STREAM-END -// -// We pass the information about the input stream encoding with the -// STREAM-START token. -// -// The next two tokens are responsible for tags: -// -// VERSION-DIRECTIVE(major,minor) -// TAG-DIRECTIVE(handle,prefix) -// -// Example: -// -// %YAML 1.1 -// %TAG ! !foo -// %TAG !yaml! tag:yaml.org,2002: -// --- -// -// The correspoding sequence of tokens: -// -// STREAM-START(utf-8) -// VERSION-DIRECTIVE(1,1) -// TAG-DIRECTIVE("!","!foo") -// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") -// DOCUMENT-START -// STREAM-END -// -// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole -// line. -// -// The document start and end indicators are represented by: -// -// DOCUMENT-START -// DOCUMENT-END -// -// Note that if a YAML stream contains an implicit document (without '---' -// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be -// produced. -// -// In the following examples, we present whole documents together with the -// produced tokens. -// -// 1. An implicit document: -// -// 'a scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// STREAM-END -// -// 2. An explicit document: -// -// --- -// 'a scalar' -// ... -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// SCALAR("a scalar",single-quoted) -// DOCUMENT-END -// STREAM-END -// -// 3. Several documents in a stream: -// -// 'a scalar' -// --- -// 'another scalar' -// --- -// 'yet another scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// DOCUMENT-START -// SCALAR("another scalar",single-quoted) -// DOCUMENT-START -// SCALAR("yet another scalar",single-quoted) -// STREAM-END -// -// We have already introduced the SCALAR token above. The following tokens are -// used to describe aliases, anchors, tag, and scalars: -// -// ALIAS(anchor) -// ANCHOR(anchor) -// TAG(handle,suffix) -// SCALAR(value,style) -// -// The following series of examples illustrate the usage of these tokens: -// -// 1. A recursive sequence: -// -// &A [ *A ] -// -// Tokens: -// -// STREAM-START(utf-8) -// ANCHOR("A") -// FLOW-SEQUENCE-START -// ALIAS("A") -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A tagged scalar: -// -// !!float "3.14" # A good approximation. -// -// Tokens: -// -// STREAM-START(utf-8) -// TAG("!!","float") -// SCALAR("3.14",double-quoted) -// STREAM-END -// -// 3. Various scalar styles: -// -// --- # Implicit empty plain scalars do not produce tokens. -// --- a plain scalar -// --- 'a single-quoted scalar' -// --- "a double-quoted scalar" -// --- |- -// a literal scalar -// --- >- -// a folded -// scalar -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// DOCUMENT-START -// SCALAR("a plain scalar",plain) -// DOCUMENT-START -// SCALAR("a single-quoted scalar",single-quoted) -// DOCUMENT-START -// SCALAR("a double-quoted scalar",double-quoted) -// DOCUMENT-START -// SCALAR("a literal scalar",literal) -// DOCUMENT-START -// SCALAR("a folded scalar",folded) -// STREAM-END -// -// Now it's time to review collection-related tokens. We will start with -// flow collections: -// -// FLOW-SEQUENCE-START -// FLOW-SEQUENCE-END -// FLOW-MAPPING-START -// FLOW-MAPPING-END -// FLOW-ENTRY -// KEY -// VALUE -// -// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and -// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' -// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the -// indicators '?' and ':', which are used for denoting mapping keys and values, -// are represented by the KEY and VALUE tokens. -// -// The following examples show flow collections: -// -// 1. A flow sequence: -// -// [item 1, item 2, item 3] -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-SEQUENCE-START -// SCALAR("item 1",plain) -// FLOW-ENTRY -// SCALAR("item 2",plain) -// FLOW-ENTRY -// SCALAR("item 3",plain) -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A flow mapping: -// -// { -// a simple key: a value, # Note that the KEY token is produced. -// ? a complex key: another value, -// } -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// FLOW-ENTRY -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// FLOW-ENTRY -// FLOW-MAPPING-END -// STREAM-END -// -// A simple key is a key which is not denoted by the '?' indicator. Note that -// the Scanner still produce the KEY token whenever it encounters a simple key. -// -// For scanning block collections, the following tokens are used (note that we -// repeat KEY and VALUE here): -// -// BLOCK-SEQUENCE-START -// BLOCK-MAPPING-START -// BLOCK-END -// BLOCK-ENTRY -// KEY -// VALUE -// -// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation -// increase that precedes a block collection (cf. the INDENT token in Python). -// The token BLOCK-END denote indentation decrease that ends a block collection -// (cf. the DEDENT token in Python). However YAML has some syntax pecularities -// that makes detections of these tokens more complex. -// -// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators -// '-', '?', and ':' correspondingly. -// -// The following examples show how the tokens BLOCK-SEQUENCE-START, -// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: -// -// 1. Block sequences: -// -// - item 1 -// - item 2 -// - -// - item 3.1 -// - item 3.2 -// - -// key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 3.1",plain) -// BLOCK-ENTRY -// SCALAR("item 3.2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Block mappings: -// -// a simple key: a value # The KEY token is produced here. -// ? a complex key -// : another value -// a mapping: -// key 1: value 1 -// key 2: value 2 -// a sequence: -// - item 1 -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// KEY -// SCALAR("a mapping",plain) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML does not always require to start a new block collection from a new -// line. If the current line contains only '-', '?', and ':' indicators, a new -// block collection may start at the current line. The following examples -// illustrate this case: -// -// 1. Collections in a sequence: -// -// - - item 1 -// - item 2 -// - key 1: value 1 -// key 2: value 2 -// - ? complex key -// : complex value -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("complex key") -// VALUE -// SCALAR("complex value") -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Collections in a mapping: -// -// ? a sequence -// : - item 1 -// - item 2 -// ? a mapping -// : key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// KEY -// SCALAR("a mapping",plain) -// VALUE -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML also permits non-indented sequences if they are included into a block -// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: -// -// key: -// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key",plain) -// VALUE -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// - -// Ensure that the buffer contains the required number of characters. -// Return true on success, false on failure (reader error or memory error). -func cache(parser *yaml_parser_t, length int) bool { - // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) - return parser.unread >= length || yaml_parser_update_buffer(parser, length) -} - -// Advance the buffer pointer. -func skip(parser *yaml_parser_t) { - parser.mark.index++ - parser.mark.column++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) -} - -func skip_line(parser *yaml_parser_t) { - if is_crlf(parser.buffer, parser.buffer_pos) { - parser.mark.index += 2 - parser.mark.column = 0 - parser.mark.line++ - parser.unread -= 2 - parser.buffer_pos += 2 - } else if is_break(parser.buffer, parser.buffer_pos) { - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) - } -} - -// Copy a character to a string buffer and advance pointers. -func read(parser *yaml_parser_t, s []byte) []byte { - w := width(parser.buffer[parser.buffer_pos]) - if w == 0 { - panic("invalid character sequence") - } - if len(s) == 0 { - s = make([]byte, 0, 32) - } - if w == 1 && len(s)+w <= cap(s) { - s = s[:len(s)+1] - s[len(s)-1] = parser.buffer[parser.buffer_pos] - parser.buffer_pos++ - } else { - s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) - parser.buffer_pos += w - } - parser.mark.index++ - parser.mark.column++ - parser.unread-- - return s -} - -// Copy a line break character to a string buffer and advance pointers. -func read_line(parser *yaml_parser_t, s []byte) []byte { - buf := parser.buffer - pos := parser.buffer_pos - switch { - case buf[pos] == '\r' && buf[pos+1] == '\n': - // CR LF . LF - s = append(s, '\n') - parser.buffer_pos += 2 - parser.mark.index++ - parser.unread-- - case buf[pos] == '\r' || buf[pos] == '\n': - // CR|LF . LF - s = append(s, '\n') - parser.buffer_pos += 1 - case buf[pos] == '\xC2' && buf[pos+1] == '\x85': - // NEL . LF - s = append(s, '\n') - parser.buffer_pos += 2 - case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): - // LS|PS . LS|PS - s = append(s, buf[parser.buffer_pos:pos+3]...) - parser.buffer_pos += 3 - default: - return s - } - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - return s -} - -// Get the next token. -func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { - // Erase the token object. - *token = yaml_token_t{} // [Go] Is this necessary? - - // No tokens after STREAM-END or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR { - return true - } - - // Ensure that the tokens queue contains enough tokens. - if !parser.token_available { - if !yaml_parser_fetch_more_tokens(parser) { - return false - } - } - - // Fetch the next token from the queue. - *token = parser.tokens[parser.tokens_head] - parser.tokens_head++ - parser.tokens_parsed++ - parser.token_available = false - - if token.typ == yaml_STREAM_END_TOKEN { - parser.stream_end_produced = true - } - return true -} - -// Set the scanner error and return false. -func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { - parser.error = yaml_SCANNER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = parser.mark - return false -} - -func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { - context := "while parsing a tag" - if directive { - context = "while parsing a %TAG directive" - } - return yaml_parser_set_scanner_error(parser, context, context_mark, problem) -} - -func trace(args ...interface{}) func() { - pargs := append([]interface{}{"+++"}, args...) - fmt.Println(pargs...) - pargs = append([]interface{}{"---"}, args...) - return func() { fmt.Println(pargs...) } -} - -// Ensure that the tokens queue contains at least one token which can be -// returned to the Parser. -func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { - // While we need more tokens to fetch, do it. - for { - if parser.tokens_head != len(parser.tokens) { - // If queue is non-empty, check if any potential simple key may - // occupy the head position. - head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed] - if !ok { - break - } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok { - return false - } else if !valid { - break - } - } - // Fetch the next token. - if !yaml_parser_fetch_next_token(parser) { - return false - } - } - - parser.token_available = true - return true -} - -// The dispatcher for token fetchers. -func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { - // Ensure that the buffer is initialized. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we just started scanning. Fetch STREAM-START then. - if !parser.stream_start_produced { - return yaml_parser_fetch_stream_start(parser) - } - - // Eat whitespaces and comments until we reach the next token. - if !yaml_parser_scan_to_next_token(parser) { - return false - } - - // Check the indentation level against the current column. - if !yaml_parser_unroll_indent(parser, parser.mark.column) { - return false - } - - // Ensure that the buffer contains at least 4 characters. 4 is the length - // of the longest indicators ('--- ' and '... '). - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - // Is it the end of the stream? - if is_z(parser.buffer, parser.buffer_pos) { - return yaml_parser_fetch_stream_end(parser) - } - - // Is it a directive? - if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { - return yaml_parser_fetch_directive(parser) - } - - buf := parser.buffer - pos := parser.buffer_pos - - // Is it the document start indicator? - if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) - } - - // Is it the document end indicator? - if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) - } - - // Is it the flow sequence start indicator? - if buf[pos] == '[' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) - } - - // Is it the flow mapping start indicator? - if parser.buffer[parser.buffer_pos] == '{' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) - } - - // Is it the flow sequence end indicator? - if parser.buffer[parser.buffer_pos] == ']' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_SEQUENCE_END_TOKEN) - } - - // Is it the flow mapping end indicator? - if parser.buffer[parser.buffer_pos] == '}' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_MAPPING_END_TOKEN) - } - - // Is it the flow entry indicator? - if parser.buffer[parser.buffer_pos] == ',' { - return yaml_parser_fetch_flow_entry(parser) - } - - // Is it the block entry indicator? - if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { - return yaml_parser_fetch_block_entry(parser) - } - - // Is it the key indicator? - if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_key(parser) - } - - // Is it the value indicator? - if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_value(parser) - } - - // Is it an alias? - if parser.buffer[parser.buffer_pos] == '*' { - return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) - } - - // Is it an anchor? - if parser.buffer[parser.buffer_pos] == '&' { - return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) - } - - // Is it a tag? - if parser.buffer[parser.buffer_pos] == '!' { - return yaml_parser_fetch_tag(parser) - } - - // Is it a literal scalar? - if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, true) - } - - // Is it a folded scalar? - if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, false) - } - - // Is it a single-quoted scalar? - if parser.buffer[parser.buffer_pos] == '\'' { - return yaml_parser_fetch_flow_scalar(parser, true) - } - - // Is it a double-quoted scalar? - if parser.buffer[parser.buffer_pos] == '"' { - return yaml_parser_fetch_flow_scalar(parser, false) - } - - // Is it a plain scalar? - // - // A plain scalar may start with any non-blank characters except - // - // '-', '?', ':', ',', '[', ']', '{', '}', - // '#', '&', '*', '!', '|', '>', '\'', '\"', - // '%', '@', '`'. - // - // In the block context (and, for the '-' indicator, in the flow context - // too), it may also start with the characters - // - // '-', '?', ':' - // - // if it is followed by a non-space character. - // - // The last rule is more restrictive than the specification requires. - // [Go] Make this logic more reasonable. - //switch parser.buffer[parser.buffer_pos] { - //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': - //} - if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || - parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || - parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || - (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level == 0 && - (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && - !is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_plain_scalar(parser) - } - - // If we don't determine the token type so far, it is an error. - return yaml_parser_set_scanner_error(parser, - "while scanning for the next token", parser.mark, - "found character that cannot start any token") -} - -func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) { - if !simple_key.possible { - return false, true - } - - // The 1.2 specification says: - // - // "If the ? indicator is omitted, parsing needs to see past the - // implicit key to recognize it as such. To limit the amount of - // lookahead required, the “:” indicator must appear at most 1024 - // Unicode characters beyond the start of the key. In addition, the key - // is restricted to a single line." - // - if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index { - // Check if the potential simple key to be removed is required. - if simple_key.required { - return false, yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key.mark, - "could not find expected ':'") - } - simple_key.possible = false - return false, true - } - return true, true -} - -// Check if a simple key may start at the current position and add it if -// needed. -func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { - // A simple key is required at the current position if the scanner is in - // the block context and the current column coincides with the indentation - // level. - - required := parser.flow_level == 0 && parser.indent == parser.mark.column - - // - // If the current position may start a simple key, save it. - // - if parser.simple_key_allowed { - simple_key := yaml_simple_key_t{ - possible: true, - required: required, - token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), - mark: parser.mark, - } - - if !yaml_parser_remove_simple_key(parser) { - return false - } - parser.simple_keys[len(parser.simple_keys)-1] = simple_key - parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1 - } - return true -} - -// Remove a potential simple key at the current flow level. -func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { - i := len(parser.simple_keys) - 1 - if parser.simple_keys[i].possible { - // If the key is required, it is an error. - if parser.simple_keys[i].required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", parser.simple_keys[i].mark, - "could not find expected ':'") - } - // Remove the key from the stack. - parser.simple_keys[i].possible = false - delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number) - } - return true -} - -// max_flow_level limits the flow_level -const max_flow_level = 10000 - -// Increase the flow level and resize the simple key list if needed. -func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { - // Reset the simple key on the next level. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{ - possible: false, - required: false, - token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), - mark: parser.mark, - }) - - // Increase the flow level. - parser.flow_level++ - if parser.flow_level > max_flow_level { - return yaml_parser_set_scanner_error(parser, - "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark, - fmt.Sprintf("exceeded max depth of %d", max_flow_level)) - } - return true -} - -// Decrease the flow level. -func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { - if parser.flow_level > 0 { - parser.flow_level-- - last := len(parser.simple_keys) - 1 - delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number) - parser.simple_keys = parser.simple_keys[:last] - } - return true -} - -// max_indents limits the indents stack size -const max_indents = 10000 - -// Push the current indentation level to the stack and set the new level -// the current column is greater than the indentation level. In this case, -// append or insert the specified token into the token queue. -func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - if parser.indent < column { - // Push the current indentation level to the stack and set the new - // indentation level. - parser.indents = append(parser.indents, parser.indent) - parser.indent = column - if len(parser.indents) > max_indents { - return yaml_parser_set_scanner_error(parser, - "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark, - fmt.Sprintf("exceeded max depth of %d", max_indents)) - } - - // Create a token and insert it into the queue. - token := yaml_token_t{ - typ: typ, - start_mark: mark, - end_mark: mark, - } - if number > -1 { - number -= parser.tokens_parsed - } - yaml_insert_token(parser, number, &token) - } - return true -} - -// Pop indentation levels from the indents stack until the current level -// becomes less or equal to the column. For each indentation level, append -// the BLOCK-END token. -func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - // Loop through the indentation levels in the stack. - for parser.indent > column { - // Create a token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - - // Pop the indentation level. - parser.indent = parser.indents[len(parser.indents)-1] - parser.indents = parser.indents[:len(parser.indents)-1] - } - return true -} - -// Initialize the scanner and produce the STREAM-START token. -func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { - - // Set the initial indentation. - parser.indent = -1 - - // Initialize the simple key stack. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - parser.simple_keys_by_tok = make(map[int]int) - - // A simple key is allowed at the beginning of the stream. - parser.simple_key_allowed = true - - // We have started. - parser.stream_start_produced = true - - // Create the STREAM-START token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_START_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - encoding: parser.encoding, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the STREAM-END token and shut down the scanner. -func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { - - // Force new line. - if parser.mark.column != 0 { - parser.mark.column = 0 - parser.mark.line++ - } - - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the STREAM-END token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. -func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. - token := yaml_token_t{} - if !yaml_parser_scan_directive(parser, &token) { - return false - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the DOCUMENT-START or DOCUMENT-END token. -func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Consume the token. - start_mark := parser.mark - - skip(parser) - skip(parser) - skip(parser) - - end_mark := parser.mark - - // Create the DOCUMENT-START or DOCUMENT-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. -func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // The indicators '[' and '{' may start a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // Increase the flow level. - if !yaml_parser_increase_flow_level(parser) { - return false - } - - // A simple key may follow the indicators '[' and '{'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. -func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset any potential simple key on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Decrease the flow level. - if !yaml_parser_decrease_flow_level(parser) { - return false - } - - // No simple keys after the indicators ']' and '}'. - parser.simple_key_allowed = false - - // Consume the token. - - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-ENTRY token. -func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after ','. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_FLOW_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the BLOCK-ENTRY token. -func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { - // Check if the scanner is in the block context. - if parser.flow_level == 0 { - // Check if we are allowed to start a new entry. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "block sequence entries are not allowed in this context") - } - // Add the BLOCK-SEQUENCE-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { - return false - } - } else { - // It is an error for the '-' indicator to occur in the flow context, - // but we let the Parser detect and report about it because the Parser - // is able to point to the context. - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '-'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the BLOCK-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the KEY token. -func yaml_parser_fetch_key(parser *yaml_parser_t) bool { - - // In the block context, additional checks are required. - if parser.flow_level == 0 { - // Check if we are allowed to start a new key (not nessesary simple). - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping keys are not allowed in this context") - } - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '?' in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the KEY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the VALUE token. -func yaml_parser_fetch_value(parser *yaml_parser_t) bool { - - simple_key := &parser.simple_keys[len(parser.simple_keys)-1] - - // Have we found a simple key? - if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok { - return false - - } else if valid { - - // Create the KEY token and insert it into the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: simple_key.mark, - end_mark: simple_key.mark, - } - yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) - - // In the block context, we may need to add the BLOCK-MAPPING-START token. - if !yaml_parser_roll_indent(parser, simple_key.mark.column, - simple_key.token_number, - yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { - return false - } - - // Remove the simple key. - simple_key.possible = false - delete(parser.simple_keys_by_tok, simple_key.token_number) - - // A simple key cannot follow another simple key. - parser.simple_key_allowed = false - - } else { - // The ':' indicator follows a complex key. - - // In the block context, extra checks are required. - if parser.flow_level == 0 { - - // Check if we are allowed to start a complex value. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping values are not allowed in this context") - } - - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Simple keys after ':' are allowed in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - } - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the VALUE token and append it to the queue. - token := yaml_token_t{ - typ: yaml_VALUE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the ALIAS or ANCHOR token. -func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // An anchor or an alias could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow an anchor or an alias. - parser.simple_key_allowed = false - - // Create the ALIAS or ANCHOR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_anchor(parser, &token, typ) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the TAG token. -func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { - // A tag could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a tag. - parser.simple_key_allowed = false - - // Create the TAG token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_tag(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. -func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { - // Remove any potential simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // A simple key may follow a block scalar. - parser.simple_key_allowed = true - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_block_scalar(parser, &token, literal) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. -func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_flow_scalar(parser, &token, single) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,plain) token. -func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_plain_scalar(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Eat whitespaces and comments until the next token is found. -func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { - - // Until the next token is not found. - for { - // Allow the BOM mark to start a line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { - skip(parser) - } - - // Eat whitespaces. - // Tabs are allowed: - // - in the flow context - // - in the block context, but not at the beginning of the line or - // after '-', '?', or ':' (complex value). - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Eat a comment until a line break. - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // If it is a line break, eat it. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - - // In the block context, a new line may start a simple key. - if parser.flow_level == 0 { - parser.simple_key_allowed = true - } - } else { - break // We have found a token. - } - } - - return true -} - -// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { - // Eat '%'. - start_mark := parser.mark - skip(parser) - - // Scan the directive name. - var name []byte - if !yaml_parser_scan_directive_name(parser, start_mark, &name) { - return false - } - - // Is it a YAML directive? - if bytes.Equal(name, []byte("YAML")) { - // Scan the VERSION directive value. - var major, minor int8 - if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { - return false - } - end_mark := parser.mark - - // Create a VERSION-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_VERSION_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - major: major, - minor: minor, - } - - // Is it a TAG directive? - } else if bytes.Equal(name, []byte("TAG")) { - // Scan the TAG directive value. - var handle, prefix []byte - if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { - return false - } - end_mark := parser.mark - - // Create a TAG-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_TAG_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - prefix: prefix, - } - - // Unknown directive. - } else { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unknown directive name") - return false - } - - // Eat the rest of the line including any comments. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - return true -} - -// Scan the directive name. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^ -// -func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { - // Consume the directive name. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - var s []byte - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the name is empty. - if len(s) == 0 { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "could not find expected directive name") - return false - } - - // Check for an blank character after the name. - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unexpected non-alphabetical character") - return false - } - *name = s - return true -} - -// Scan the value of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^ -func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the major version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { - return false - } - - // Eat '.'. - if parser.buffer[parser.buffer_pos] != '.' { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected digit or '.' character") - } - - skip(parser) - - // Consume the minor version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { - return false - } - return true -} - -const max_number_length = 2 - -// Scan the version number of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^ -// %YAML 1.1 # a comment \n -// ^ -func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { - - // Repeat while the next character is digit. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var value, length int8 - for is_digit(parser.buffer, parser.buffer_pos) { - // Check if the number is too long. - length++ - if length > max_number_length { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "found extremely long version number") - } - value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the number was present. - if length == 0 { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected version number") - } - *number = value - return true -} - -// Scan the value of a TAG-DIRECTIVE token. -// -// Scope: -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { - var handle_value, prefix_value []byte - - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a handle. - if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { - return false - } - - // Expect a whitespace. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blank(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace") - return false - } - - // Eat whitespaces. - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a prefix. - if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { - return false - } - - // Expect a whitespace or line break. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace or line break") - return false - } - - *handle = handle_value - *prefix = prefix_value - return true -} - -func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { - var s []byte - - // Eat the indicator character. - start_mark := parser.mark - skip(parser) - - // Consume the value. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - end_mark := parser.mark - - /* - * Check if length of the anchor is greater than 0 and it is followed by - * a whitespace character or one of the indicators: - * - * '?', ':', ',', ']', '}', '%', '@', '`'. - */ - - if len(s) == 0 || - !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || - parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '`') { - context := "while scanning an alias" - if typ == yaml_ANCHOR_TOKEN { - context = "while scanning an anchor" - } - yaml_parser_set_scanner_error(parser, context, start_mark, - "did not find expected alphabetic or numeric character") - return false - } - - // Create a token. - *token = yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - value: s, - } - - return true -} - -/* - * Scan a TAG token. - */ - -func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { - var handle, suffix []byte - - start_mark := parser.mark - - // Check if the tag is in the canonical form. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - if parser.buffer[parser.buffer_pos+1] == '<' { - // Keep the handle as '' - - // Eat '!<' - skip(parser) - skip(parser) - - // Consume the tag value. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - - // Check for '>' and eat it. - if parser.buffer[parser.buffer_pos] != '>' { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find the expected '>'") - return false - } - - skip(parser) - } else { - // The tag has either the '!suffix' or the '!handle!suffix' form. - - // First, try to scan a handle. - if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { - return false - } - - // Check if it is, indeed, handle. - if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { - // Scan the suffix now. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - } else { - // It wasn't a handle after all. Scan the rest of the tag. - if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { - return false - } - - // Set the handle to '!'. - handle = []byte{'!'} - - // A special case: the '!' tag. Set the handle to '' and the - // suffix to '!'. - if len(suffix) == 0 { - handle, suffix = suffix, handle - } - } - } - - // Check the character which ends the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find expected whitespace or line break") - return false - } - - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_TAG_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - suffix: suffix, - } - return true -} - -// Scan a tag handle. -func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { - // Check the initial '!' character. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] != '!' { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - - var s []byte - - // Copy the '!' character. - s = read(parser, s) - - // Copy all subsequent alphabetical and numerical characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the trailing character is '!' and copy it. - if parser.buffer[parser.buffer_pos] == '!' { - s = read(parser, s) - } else { - // It's either the '!' tag or not really a tag handle. If it's a %TAG - // directive, it's an error. If it's a tag token, it must be a part of URI. - if directive && string(s) != "!" { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - } - - *handle = s - return true -} - -// Scan a tag. -func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { - //size_t length = head ? strlen((char *)head) : 0 - var s []byte - hasTag := len(head) > 0 - - // Copy the head if needed. - // - // Note that we don't copy the leading '!' character. - if len(head) > 1 { - s = append(s, head[1:]...) - } - - // Scan the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // The set of characters that may appear in URI is as follows: - // - // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', - // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', - // '%'. - // [Go] Convert this into more reasonable logic. - for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || - parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || - parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || - parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || - parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || - parser.buffer[parser.buffer_pos] == '%' { - // Check if it is a URI-escape sequence. - if parser.buffer[parser.buffer_pos] == '%' { - if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { - return false - } - } else { - s = read(parser, s) - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - hasTag = true - } - - if !hasTag { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected tag URI") - return false - } - *uri = s - return true -} - -// Decode an URI-escape sequence corresponding to a single UTF-8 character. -func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { - - // Decode the required number of characters. - w := 1024 - for w > 0 { - // Check for a URI-escaped octet. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - - if !(parser.buffer[parser.buffer_pos] == '%' && - is_hex(parser.buffer, parser.buffer_pos+1) && - is_hex(parser.buffer, parser.buffer_pos+2)) { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find URI escaped octet") - } - - // Get the octet. - octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) - - // If it is the leading octet, determine the length of the UTF-8 sequence. - if w == 1024 { - w = width(octet) - if w == 0 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect leading UTF-8 octet") - } - } else { - // Check if the trailing octet is correct. - if octet&0xC0 != 0x80 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect trailing UTF-8 octet") - } - } - - // Copy the octet and move the pointers. - *s = append(*s, octet) - skip(parser) - skip(parser) - skip(parser) - w-- - } - return true -} - -// Scan a block scalar. -func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { - // Eat the indicator '|' or '>'. - start_mark := parser.mark - skip(parser) - - // Scan the additional block scalar indicators. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check for a chomping indicator. - var chomping, increment int - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - // Set the chomping method and eat the indicator. - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - - // Check for an indentation indicator. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if is_digit(parser.buffer, parser.buffer_pos) { - // Check that the indentation is greater than 0. - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - - // Get the indentation level and eat the indicator. - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - } - - } else if is_digit(parser.buffer, parser.buffer_pos) { - // Do the same as above, but in the opposite order. - - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - } - } - - // Eat whitespaces and comments to the end of the line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - end_mark := parser.mark - - // Set the indentation level if it was specified. - var indent int - if increment > 0 { - if parser.indent >= 0 { - indent = parser.indent + increment - } else { - indent = increment - } - } - - // Scan the leading line breaks and determine the indentation level if needed. - var s, leading_break, trailing_breaks []byte - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - - // Scan the block scalar content. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var leading_blank, trailing_blank bool - for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { - // We are at the beginning of a non-empty line. - - // Is it a trailing whitespace? - trailing_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Check if we need to fold the leading line break. - if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { - // Do we need to join the lines by space? - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } - } else { - s = append(s, leading_break...) - } - leading_break = leading_break[:0] - - // Append the remaining line breaks. - s = append(s, trailing_breaks...) - trailing_breaks = trailing_breaks[:0] - - // Is it a leading whitespace? - leading_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Consume the current line. - for !is_breakz(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - leading_break = read_line(parser, leading_break) - - // Eat the following indentation spaces and line breaks. - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - } - - // Chomp the tail. - if chomping != -1 { - s = append(s, leading_break...) - } - if chomping == 1 { - s = append(s, trailing_breaks...) - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_LITERAL_SCALAR_STYLE, - } - if !literal { - token.style = yaml_FOLDED_SCALAR_STYLE - } - return true -} - -// Scan indentation spaces and line breaks for a block scalar. Determine the -// indentation level if needed. -func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { - *end_mark = parser.mark - - // Eat the indentation spaces and line breaks. - max_indent := 0 - for { - // Eat the indentation spaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.mark.column > max_indent { - max_indent = parser.mark.column - } - - // Check for a tab character messing the indentation. - if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { - return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found a tab character where an indentation space is expected") - } - - // Have we found a non-empty line? - if !is_break(parser.buffer, parser.buffer_pos) { - break - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - // [Go] Should really be returning breaks instead. - *breaks = read_line(parser, *breaks) - *end_mark = parser.mark - } - - // Determine the indentation level if needed. - if *indent == 0 { - *indent = max_indent - if *indent < parser.indent+1 { - *indent = parser.indent + 1 - } - if *indent < 1 { - *indent = 1 - } - } - return true -} - -// Scan a quoted scalar. -func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { - // Eat the left quote. - start_mark := parser.mark - skip(parser) - - // Consume the content of the quoted scalar. - var s, leading_break, trailing_breaks, whitespaces []byte - for { - // Check that there are no document indicators at the beginning of the line. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected document indicator") - return false - } - - // Check for EOF. - if is_z(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected end of stream") - return false - } - - // Consume non-blank characters. - leading_blanks := false - for !is_blankz(parser.buffer, parser.buffer_pos) { - if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { - // Is is an escaped single quote. - s = append(s, '\'') - skip(parser) - skip(parser) - - } else if single && parser.buffer[parser.buffer_pos] == '\'' { - // It is a right single quote. - break - } else if !single && parser.buffer[parser.buffer_pos] == '"' { - // It is a right double quote. - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { - // It is an escaped line break. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - skip(parser) - skip_line(parser) - leading_blanks = true - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' { - // It is an escape sequence. - code_length := 0 - - // Check the escape character. - switch parser.buffer[parser.buffer_pos+1] { - case '0': - s = append(s, 0) - case 'a': - s = append(s, '\x07') - case 'b': - s = append(s, '\x08') - case 't', '\t': - s = append(s, '\x09') - case 'n': - s = append(s, '\x0A') - case 'v': - s = append(s, '\x0B') - case 'f': - s = append(s, '\x0C') - case 'r': - s = append(s, '\x0D') - case 'e': - s = append(s, '\x1B') - case ' ': - s = append(s, '\x20') - case '"': - s = append(s, '"') - case '\'': - s = append(s, '\'') - case '\\': - s = append(s, '\\') - case 'N': // NEL (#x85) - s = append(s, '\xC2') - s = append(s, '\x85') - case '_': // #xA0 - s = append(s, '\xC2') - s = append(s, '\xA0') - case 'L': // LS (#x2028) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA8') - case 'P': // PS (#x2029) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA9') - case 'x': - code_length = 2 - case 'u': - code_length = 4 - case 'U': - code_length = 8 - default: - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found unknown escape character") - return false - } - - skip(parser) - skip(parser) - - // Consume an arbitrary escape code. - if code_length > 0 { - var value int - - // Scan the character value. - if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { - return false - } - for k := 0; k < code_length; k++ { - if !is_hex(parser.buffer, parser.buffer_pos+k) { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "did not find expected hexdecimal number") - return false - } - value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) - } - - // Check the value and write the character. - if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found invalid Unicode character escape code") - return false - } - if value <= 0x7F { - s = append(s, byte(value)) - } else if value <= 0x7FF { - s = append(s, byte(0xC0+(value>>6))) - s = append(s, byte(0x80+(value&0x3F))) - } else if value <= 0xFFFF { - s = append(s, byte(0xE0+(value>>12))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } else { - s = append(s, byte(0xF0+(value>>18))) - s = append(s, byte(0x80+((value>>12)&0x3F))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } - - // Advance the pointer. - for k := 0; k < code_length; k++ { - skip(parser) - } - } - } else { - // It is a non-escaped non-blank character. - s = read(parser, s) - } - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we are at the end of the scalar. - if single { - if parser.buffer[parser.buffer_pos] == '\'' { - break - } - } else { - if parser.buffer[parser.buffer_pos] == '"' { - break - } - } - - // Consume blank characters. - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Join the whitespaces or fold line breaks. - if leading_blanks { - // Do we need to fold line breaks? - if len(leading_break) > 0 && leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Eat the right quote. - skip(parser) - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_SINGLE_QUOTED_SCALAR_STYLE, - } - if !single { - token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - return true -} - -// Scan a plain scalar. -func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { - - var s, leading_break, trailing_breaks, whitespaces []byte - var leading_blanks bool - var indent = parser.indent + 1 - - start_mark := parser.mark - end_mark := parser.mark - - // Consume the content of the plain scalar. - for { - // Check for a document indicator. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - break - } - - // Check for a comment. - if parser.buffer[parser.buffer_pos] == '#' { - break - } - - // Consume non-blank characters. - for !is_blankz(parser.buffer, parser.buffer_pos) { - - // Check for indicators that may end a plain scalar. - if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level > 0 && - (parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}')) { - break - } - - // Check if we need to join whitespaces and breaks. - if leading_blanks || len(whitespaces) > 0 { - if leading_blanks { - // Do we need to fold line breaks? - if leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - leading_blanks = false - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Copy the character. - s = read(parser, s) - - end_mark = parser.mark - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - // Is it the end? - if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { - break - } - - // Consume blank characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - - // Check for tab characters that abuse indentation. - if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found a tab character that violates indentation") - return false - } - - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check indentation level. - if parser.flow_level == 0 && parser.mark.column < indent { - break - } - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_PLAIN_SCALAR_STYLE, - } - - // Note that we change the 'simple_key_allowed' flag. - if leading_blanks { - parser.simple_key_allowed = true - } - return true -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/sorter.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/sorter.go deleted file mode 100644 index 4c45e660a8..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/sorter.go +++ /dev/null @@ -1,113 +0,0 @@ -package yaml - -import ( - "reflect" - "unicode" -) - -type keyList []reflect.Value - -func (l keyList) Len() int { return len(l) } -func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } -func (l keyList) Less(i, j int) bool { - a := l[i] - b := l[j] - ak := a.Kind() - bk := b.Kind() - for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { - a = a.Elem() - ak = a.Kind() - } - for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { - b = b.Elem() - bk = b.Kind() - } - af, aok := keyFloat(a) - bf, bok := keyFloat(b) - if aok && bok { - if af != bf { - return af < bf - } - if ak != bk { - return ak < bk - } - return numLess(a, b) - } - if ak != reflect.String || bk != reflect.String { - return ak < bk - } - ar, br := []rune(a.String()), []rune(b.String()) - for i := 0; i < len(ar) && i < len(br); i++ { - if ar[i] == br[i] { - continue - } - al := unicode.IsLetter(ar[i]) - bl := unicode.IsLetter(br[i]) - if al && bl { - return ar[i] < br[i] - } - if al || bl { - return bl - } - var ai, bi int - var an, bn int64 - if ar[i] == '0' || br[i] == '0' { - for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { - if ar[j] != '0' { - an = 1 - bn = 1 - break - } - } - } - for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { - an = an*10 + int64(ar[ai]-'0') - } - for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { - bn = bn*10 + int64(br[bi]-'0') - } - if an != bn { - return an < bn - } - if ai != bi { - return ai < bi - } - return ar[i] < br[i] - } - return len(ar) < len(br) -} - -// keyFloat returns a float value for v if it is a number/bool -// and whether it is a number/bool or not. -func keyFloat(v reflect.Value) (f float64, ok bool) { - switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return float64(v.Int()), true - case reflect.Float32, reflect.Float64: - return v.Float(), true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return float64(v.Uint()), true - case reflect.Bool: - if v.Bool() { - return 1, true - } - return 0, true - } - return 0, false -} - -// numLess returns whether a < b. -// a and b must necessarily have the same kind. -func numLess(a, b reflect.Value) bool { - switch a.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return a.Int() < b.Int() - case reflect.Float32, reflect.Float64: - return a.Float() < b.Float() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return a.Uint() < b.Uint() - case reflect.Bool: - return !a.Bool() && b.Bool() - } - panic("not a number") -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/writerc.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/writerc.go deleted file mode 100644 index a2dde608cb..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/writerc.go +++ /dev/null @@ -1,26 +0,0 @@ -package yaml - -// Set the writer error and return false. -func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_WRITER_ERROR - emitter.problem = problem - return false -} - -// Flush the output buffer. -func yaml_emitter_flush(emitter *yaml_emitter_t) bool { - if emitter.write_handler == nil { - panic("write handler not set") - } - - // Check if the buffer is empty. - if emitter.buffer_pos == 0 { - return true - } - - if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { - return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) - } - emitter.buffer_pos = 0 - return true -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/yaml.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/yaml.go deleted file mode 100644 index 30813884c0..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/yaml.go +++ /dev/null @@ -1,478 +0,0 @@ -// Package yaml implements YAML support for the Go language. -// -// Source code and other details for the project are available at GitHub: -// -// https://github.com/go-yaml/yaml -// -package yaml - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "sync" -) - -// MapSlice encodes and decodes as a YAML map. -// The order of keys is preserved when encoding and decoding. -type MapSlice []MapItem - -// MapItem is an item in a MapSlice. -type MapItem struct { - Key, Value interface{} -} - -// The Unmarshaler interface may be implemented by types to customize their -// behavior when being unmarshaled from a YAML document. The UnmarshalYAML -// method receives a function that may be called to unmarshal the original -// YAML value into a field or variable. It is safe to call the unmarshal -// function parameter more than once if necessary. -type Unmarshaler interface { - UnmarshalYAML(unmarshal func(interface{}) error) error -} - -// The Marshaler interface may be implemented by types to customize their -// behavior when being marshaled into a YAML document. The returned value -// is marshaled in place of the original value implementing Marshaler. -// -// If an error is returned by MarshalYAML, the marshaling procedure stops -// and returns with the provided error. -type Marshaler interface { - MarshalYAML() (interface{}, error) -} - -// Unmarshal decodes the first document found within the in byte slice -// and assigns decoded values into the out value. -// -// Maps and pointers (to a struct, string, int, etc) are accepted as out -// values. If an internal pointer within a struct is not initialized, -// the yaml package will initialize it if necessary for unmarshalling -// the provided data. The out parameter must not be nil. -// -// The type of the decoded values should be compatible with the respective -// values in out. If one or more values cannot be decoded due to a type -// mismatches, decoding continues partially until the end of the YAML -// content, and a *yaml.TypeError is returned with details for all -// missed values. -// -// Struct fields are only unmarshalled if they are exported (have an -// upper case first letter), and are unmarshalled using the field name -// lowercased as the default key. Custom keys may be defined via the -// "yaml" name in the field tag: the content preceding the first comma -// is used as the key, and the following comma-separated options are -// used to tweak the marshalling process (see Marshal). -// Conflicting names result in a runtime error. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) -// -// See the documentation of Marshal for the format of tags and a list of -// supported tag options. -// -func Unmarshal(in []byte, out interface{}) (err error) { - return unmarshal(in, out, false) -} - -// UnmarshalStrict is like Unmarshal except that any fields that are found -// in the data that do not have corresponding struct members, or mapping -// keys that are duplicates, will result in -// an error. -func UnmarshalStrict(in []byte, out interface{}) (err error) { - return unmarshal(in, out, true) -} - -// A Decoder reads and decodes YAML values from an input stream. -type Decoder struct { - strict bool - parser *parser -} - -// NewDecoder returns a new decoder that reads from r. -// -// The decoder introduces its own buffering and may read -// data from r beyond the YAML values requested. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{ - parser: newParserFromReader(r), - } -} - -// SetStrict sets whether strict decoding behaviour is enabled when -// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict. -func (dec *Decoder) SetStrict(strict bool) { - dec.strict = strict -} - -// Decode reads the next YAML-encoded value from its input -// and stores it in the value pointed to by v. -// -// See the documentation for Unmarshal for details about the -// conversion of YAML into a Go value. -func (dec *Decoder) Decode(v interface{}) (err error) { - d := newDecoder(dec.strict) - defer handleErr(&err) - node := dec.parser.parse() - if node == nil { - return io.EOF - } - out := reflect.ValueOf(v) - if out.Kind() == reflect.Ptr && !out.IsNil() { - out = out.Elem() - } - d.unmarshal(node, out) - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -func unmarshal(in []byte, out interface{}, strict bool) (err error) { - defer handleErr(&err) - d := newDecoder(strict) - p := newParser(in) - defer p.destroy() - node := p.parse() - if node != nil { - v := reflect.ValueOf(out) - if v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - d.unmarshal(node, v) - } - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -// Marshal serializes the value provided into a YAML document. The structure -// of the generated document will reflect the structure of the value itself. -// Maps and pointers (to struct, string, int, etc) are accepted as the in value. -// -// Struct fields are only marshalled if they are exported (have an upper case -// first letter), and are marshalled using the field name lowercased as the -// default key. Custom keys may be defined via the "yaml" name in the field -// tag: the content preceding the first comma is used as the key, and the -// following comma-separated options are used to tweak the marshalling process. -// Conflicting names result in a runtime error. -// -// The field tag format accepted is: -// -// `(...) yaml:"[][,[,]]" (...)` -// -// The following flags are currently supported: -// -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be excluded if IsZero returns true. -// -// flow Marshal using a flow style (useful for structs, -// sequences and maps). -// -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. -// -// In addition, if the key is "-", the field is ignored. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" -// -func Marshal(in interface{}) (out []byte, err error) { - defer handleErr(&err) - e := newEncoder() - defer e.destroy() - e.marshalDoc("", reflect.ValueOf(in)) - e.finish() - out = e.out - return -} - -// An Encoder writes YAML values to an output stream. -type Encoder struct { - encoder *encoder -} - -// NewEncoder returns a new encoder that writes to w. -// The Encoder should be closed after use to flush all data -// to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - encoder: newEncoderWithWriter(w), - } -} - -// Encode writes the YAML encoding of v to the stream. -// If multiple items are encoded to the stream, the -// second and subsequent document will be preceded -// with a "---" document separator, but the first will not. -// -// See the documentation for Marshal for details about the conversion of Go -// values to YAML. -func (e *Encoder) Encode(v interface{}) (err error) { - defer handleErr(&err) - e.encoder.marshalDoc("", reflect.ValueOf(v)) - return nil -} - -// Close closes the encoder by writing any remaining data. -// It does not write a stream terminating string "...". -func (e *Encoder) Close() (err error) { - defer handleErr(&err) - e.encoder.finish() - return nil -} - -func handleErr(err *error) { - if v := recover(); v != nil { - if e, ok := v.(yamlError); ok { - *err = e.err - } else { - panic(v) - } - } -} - -type yamlError struct { - err error -} - -func fail(err error) { - panic(yamlError{err}) -} - -func failf(format string, args ...interface{}) { - panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) -} - -// A TypeError is returned by Unmarshal when one or more fields in -// the YAML document cannot be properly decoded into the requested -// types. When this error is returned, the value is still -// unmarshaled partially. -type TypeError struct { - Errors []string -} - -func (e *TypeError) Error() string { - return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) -} - -// -------------------------------------------------------------------------- -// Maintain a mapping of keys to structure field indexes - -// The code in this section was copied from mgo/bson. - -// structInfo holds details for the serialization of fields of -// a given struct. -type structInfo struct { - FieldsMap map[string]fieldInfo - FieldsList []fieldInfo - - // InlineMap is the number of the field in the struct that - // contains an ,inline map, or -1 if there's none. - InlineMap int -} - -type fieldInfo struct { - Key string - Num int - OmitEmpty bool - Flow bool - // Id holds the unique field identifier, so we can cheaply - // check for field duplicates without maintaining an extra map. - Id int - - // Inline holds the field index if the field is part of an inlined struct. - Inline []int -} - -var structMap = make(map[reflect.Type]*structInfo) -var fieldMapMutex sync.RWMutex - -func getStructInfo(st reflect.Type) (*structInfo, error) { - fieldMapMutex.RLock() - sinfo, found := structMap[st] - fieldMapMutex.RUnlock() - if found { - return sinfo, nil - } - - n := st.NumField() - fieldsMap := make(map[string]fieldInfo) - fieldsList := make([]fieldInfo, 0, n) - inlineMap := -1 - for i := 0; i != n; i++ { - field := st.Field(i) - if field.PkgPath != "" && !field.Anonymous { - continue // Private field - } - - info := fieldInfo{Num: i} - - tag := field.Tag.Get("yaml") - if tag == "" && strings.Index(string(field.Tag), ":") < 0 { - tag = string(field.Tag) - } - if tag == "-" { - continue - } - - inline := false - fields := strings.Split(tag, ",") - if len(fields) > 1 { - for _, flag := range fields[1:] { - switch flag { - case "omitempty": - info.OmitEmpty = true - case "flow": - info.Flow = true - case "inline": - inline = true - default: - return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) - } - } - tag = fields[0] - } - - if inline { - switch field.Type.Kind() { - case reflect.Map: - if inlineMap >= 0 { - return nil, errors.New("Multiple ,inline maps in struct " + st.String()) - } - if field.Type.Key() != reflect.TypeOf("") { - return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) - } - inlineMap = info.Num - case reflect.Struct: - sinfo, err := getStructInfo(field.Type) - if err != nil { - return nil, err - } - for _, finfo := range sinfo.FieldsList { - if _, found := fieldsMap[finfo.Key]; found { - msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - if finfo.Inline == nil { - finfo.Inline = []int{i, finfo.Num} - } else { - finfo.Inline = append([]int{i}, finfo.Inline...) - } - finfo.Id = len(fieldsList) - fieldsMap[finfo.Key] = finfo - fieldsList = append(fieldsList, finfo) - } - default: - //return nil, errors.New("Option ,inline needs a struct value or map field") - return nil, errors.New("Option ,inline needs a struct value field") - } - continue - } - - if tag != "" { - info.Key = tag - } else { - info.Key = strings.ToLower(field.Name) - } - - if _, found = fieldsMap[info.Key]; found { - msg := "Duplicated key '" + info.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - - info.Id = len(fieldsList) - fieldsList = append(fieldsList, info) - fieldsMap[info.Key] = info - } - - sinfo = &structInfo{ - FieldsMap: fieldsMap, - FieldsList: fieldsList, - InlineMap: inlineMap, - } - - fieldMapMutex.Lock() - structMap[st] = sinfo - fieldMapMutex.Unlock() - return sinfo, nil -} - -// IsZeroer is used to check whether an object is zero to -// determine whether it should be omitted when marshaling -// with the omitempty flag. One notable implementation -// is time.Time. -type IsZeroer interface { - IsZero() bool -} - -func isZero(v reflect.Value) bool { - kind := v.Kind() - if z, ok := v.Interface().(IsZeroer); ok { - if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { - return true - } - return z.IsZero() - } - switch kind { - case reflect.String: - return len(v.String()) == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - case reflect.Slice: - return v.Len() == 0 - case reflect.Map: - return v.Len() == 0 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Struct: - vt := v.Type() - for i := v.NumField() - 1; i >= 0; i-- { - if vt.Field(i).PkgPath != "" { - continue // Private field - } - if !isZero(v.Field(i)) { - return false - } - } - return true - } - return false -} - -// FutureLineWrap globally disables line wrapping when encoding long strings. -// This is a temporary and thus deprecated method introduced to faciliate -// migration towards v3, which offers more control of line lengths on -// individual encodings, and has a default matching the behavior introduced -// by this function. -// -// The default formatting of v2 was erroneously changed in v2.3.0 and reverted -// in v2.4.0, at which point this function was introduced to help migration. -func FutureLineWrap() { - disableLineWrapping = true -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/yamlh.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/yamlh.go deleted file mode 100644 index f6a9c8e34b..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/yamlh.go +++ /dev/null @@ -1,739 +0,0 @@ -package yaml - -import ( - "fmt" - "io" -) - -// The version directive data. -type yaml_version_directive_t struct { - major int8 // The major version number. - minor int8 // The minor version number. -} - -// The tag directive data. -type yaml_tag_directive_t struct { - handle []byte // The tag handle. - prefix []byte // The tag prefix. -} - -type yaml_encoding_t int - -// The stream encoding. -const ( - // Let the parser choose the encoding. - yaml_ANY_ENCODING yaml_encoding_t = iota - - yaml_UTF8_ENCODING // The default UTF-8 encoding. - yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. - yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. -) - -type yaml_break_t int - -// Line break types. -const ( - // Let the parser choose the break type. - yaml_ANY_BREAK yaml_break_t = iota - - yaml_CR_BREAK // Use CR for line breaks (Mac style). - yaml_LN_BREAK // Use LN for line breaks (Unix style). - yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). -) - -type yaml_error_type_t int - -// Many bad things could happen with the parser and emitter. -const ( - // No error is produced. - yaml_NO_ERROR yaml_error_type_t = iota - - yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. - yaml_READER_ERROR // Cannot read or decode the input stream. - yaml_SCANNER_ERROR // Cannot scan the input stream. - yaml_PARSER_ERROR // Cannot parse the input stream. - yaml_COMPOSER_ERROR // Cannot compose a YAML document. - yaml_WRITER_ERROR // Cannot write to the output stream. - yaml_EMITTER_ERROR // Cannot emit a YAML stream. -) - -// The pointer position. -type yaml_mark_t struct { - index int // The position index. - line int // The position line. - column int // The position column. -} - -// Node Styles - -type yaml_style_t int8 - -type yaml_scalar_style_t yaml_style_t - -// Scalar styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota - - yaml_PLAIN_SCALAR_STYLE // The plain scalar style. - yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. - yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. - yaml_LITERAL_SCALAR_STYLE // The literal scalar style. - yaml_FOLDED_SCALAR_STYLE // The folded scalar style. -) - -type yaml_sequence_style_t yaml_style_t - -// Sequence styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota - - yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. - yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. -) - -type yaml_mapping_style_t yaml_style_t - -// Mapping styles. -const ( - // Let the emitter choose the style. - yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota - - yaml_BLOCK_MAPPING_STYLE // The block mapping style. - yaml_FLOW_MAPPING_STYLE // The flow mapping style. -) - -// Tokens - -type yaml_token_type_t int - -// Token types. -const ( - // An empty token. - yaml_NO_TOKEN yaml_token_type_t = iota - - yaml_STREAM_START_TOKEN // A STREAM-START token. - yaml_STREAM_END_TOKEN // A STREAM-END token. - - yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. - yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. - yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. - yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. - - yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. - yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. - yaml_BLOCK_END_TOKEN // A BLOCK-END token. - - yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. - yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. - yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. - yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. - - yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. - yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. - yaml_KEY_TOKEN // A KEY token. - yaml_VALUE_TOKEN // A VALUE token. - - yaml_ALIAS_TOKEN // An ALIAS token. - yaml_ANCHOR_TOKEN // An ANCHOR token. - yaml_TAG_TOKEN // A TAG token. - yaml_SCALAR_TOKEN // A SCALAR token. -) - -func (tt yaml_token_type_t) String() string { - switch tt { - case yaml_NO_TOKEN: - return "yaml_NO_TOKEN" - case yaml_STREAM_START_TOKEN: - return "yaml_STREAM_START_TOKEN" - case yaml_STREAM_END_TOKEN: - return "yaml_STREAM_END_TOKEN" - case yaml_VERSION_DIRECTIVE_TOKEN: - return "yaml_VERSION_DIRECTIVE_TOKEN" - case yaml_TAG_DIRECTIVE_TOKEN: - return "yaml_TAG_DIRECTIVE_TOKEN" - case yaml_DOCUMENT_START_TOKEN: - return "yaml_DOCUMENT_START_TOKEN" - case yaml_DOCUMENT_END_TOKEN: - return "yaml_DOCUMENT_END_TOKEN" - case yaml_BLOCK_SEQUENCE_START_TOKEN: - return "yaml_BLOCK_SEQUENCE_START_TOKEN" - case yaml_BLOCK_MAPPING_START_TOKEN: - return "yaml_BLOCK_MAPPING_START_TOKEN" - case yaml_BLOCK_END_TOKEN: - return "yaml_BLOCK_END_TOKEN" - case yaml_FLOW_SEQUENCE_START_TOKEN: - return "yaml_FLOW_SEQUENCE_START_TOKEN" - case yaml_FLOW_SEQUENCE_END_TOKEN: - return "yaml_FLOW_SEQUENCE_END_TOKEN" - case yaml_FLOW_MAPPING_START_TOKEN: - return "yaml_FLOW_MAPPING_START_TOKEN" - case yaml_FLOW_MAPPING_END_TOKEN: - return "yaml_FLOW_MAPPING_END_TOKEN" - case yaml_BLOCK_ENTRY_TOKEN: - return "yaml_BLOCK_ENTRY_TOKEN" - case yaml_FLOW_ENTRY_TOKEN: - return "yaml_FLOW_ENTRY_TOKEN" - case yaml_KEY_TOKEN: - return "yaml_KEY_TOKEN" - case yaml_VALUE_TOKEN: - return "yaml_VALUE_TOKEN" - case yaml_ALIAS_TOKEN: - return "yaml_ALIAS_TOKEN" - case yaml_ANCHOR_TOKEN: - return "yaml_ANCHOR_TOKEN" - case yaml_TAG_TOKEN: - return "yaml_TAG_TOKEN" - case yaml_SCALAR_TOKEN: - return "yaml_SCALAR_TOKEN" - } - return "" -} - -// The token structure. -type yaml_token_t struct { - // The token type. - typ yaml_token_type_t - - // The start/end of the token. - start_mark, end_mark yaml_mark_t - - // The stream encoding (for yaml_STREAM_START_TOKEN). - encoding yaml_encoding_t - - // The alias/anchor/scalar value or tag/tag directive handle - // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). - value []byte - - // The tag suffix (for yaml_TAG_TOKEN). - suffix []byte - - // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). - prefix []byte - - // The scalar style (for yaml_SCALAR_TOKEN). - style yaml_scalar_style_t - - // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). - major, minor int8 -} - -// Events - -type yaml_event_type_t int8 - -// Event types. -const ( - // An empty event. - yaml_NO_EVENT yaml_event_type_t = iota - - yaml_STREAM_START_EVENT // A STREAM-START event. - yaml_STREAM_END_EVENT // A STREAM-END event. - yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. - yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. - yaml_ALIAS_EVENT // An ALIAS event. - yaml_SCALAR_EVENT // A SCALAR event. - yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. - yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. - yaml_MAPPING_START_EVENT // A MAPPING-START event. - yaml_MAPPING_END_EVENT // A MAPPING-END event. -) - -var eventStrings = []string{ - yaml_NO_EVENT: "none", - yaml_STREAM_START_EVENT: "stream start", - yaml_STREAM_END_EVENT: "stream end", - yaml_DOCUMENT_START_EVENT: "document start", - yaml_DOCUMENT_END_EVENT: "document end", - yaml_ALIAS_EVENT: "alias", - yaml_SCALAR_EVENT: "scalar", - yaml_SEQUENCE_START_EVENT: "sequence start", - yaml_SEQUENCE_END_EVENT: "sequence end", - yaml_MAPPING_START_EVENT: "mapping start", - yaml_MAPPING_END_EVENT: "mapping end", -} - -func (e yaml_event_type_t) String() string { - if e < 0 || int(e) >= len(eventStrings) { - return fmt.Sprintf("unknown event %d", e) - } - return eventStrings[e] -} - -// The event structure. -type yaml_event_t struct { - - // The event type. - typ yaml_event_type_t - - // The start and end of the event. - start_mark, end_mark yaml_mark_t - - // The document encoding (for yaml_STREAM_START_EVENT). - encoding yaml_encoding_t - - // The version directive (for yaml_DOCUMENT_START_EVENT). - version_directive *yaml_version_directive_t - - // The list of tag directives (for yaml_DOCUMENT_START_EVENT). - tag_directives []yaml_tag_directive_t - - // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). - anchor []byte - - // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - tag []byte - - // The scalar value (for yaml_SCALAR_EVENT). - value []byte - - // Is the document start/end indicator implicit, or the tag optional? - // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). - implicit bool - - // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). - quoted_implicit bool - - // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - style yaml_style_t -} - -func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } -func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } -func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } - -// Nodes - -const ( - yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. - yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. - yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. - yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. - yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. - yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. - - yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. - yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. - - // Not in original libyaml. - yaml_BINARY_TAG = "tag:yaml.org,2002:binary" - yaml_MERGE_TAG = "tag:yaml.org,2002:merge" - - yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. - yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. - yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. -) - -type yaml_node_type_t int - -// Node types. -const ( - // An empty node. - yaml_NO_NODE yaml_node_type_t = iota - - yaml_SCALAR_NODE // A scalar node. - yaml_SEQUENCE_NODE // A sequence node. - yaml_MAPPING_NODE // A mapping node. -) - -// An element of a sequence node. -type yaml_node_item_t int - -// An element of a mapping node. -type yaml_node_pair_t struct { - key int // The key of the element. - value int // The value of the element. -} - -// The node structure. -type yaml_node_t struct { - typ yaml_node_type_t // The node type. - tag []byte // The node tag. - - // The node data. - - // The scalar parameters (for yaml_SCALAR_NODE). - scalar struct { - value []byte // The scalar value. - length int // The length of the scalar value. - style yaml_scalar_style_t // The scalar style. - } - - // The sequence parameters (for YAML_SEQUENCE_NODE). - sequence struct { - items_data []yaml_node_item_t // The stack of sequence items. - style yaml_sequence_style_t // The sequence style. - } - - // The mapping parameters (for yaml_MAPPING_NODE). - mapping struct { - pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). - pairs_start *yaml_node_pair_t // The beginning of the stack. - pairs_end *yaml_node_pair_t // The end of the stack. - pairs_top *yaml_node_pair_t // The top of the stack. - style yaml_mapping_style_t // The mapping style. - } - - start_mark yaml_mark_t // The beginning of the node. - end_mark yaml_mark_t // The end of the node. - -} - -// The document structure. -type yaml_document_t struct { - - // The document nodes. - nodes []yaml_node_t - - // The version directive. - version_directive *yaml_version_directive_t - - // The list of tag directives. - tag_directives_data []yaml_tag_directive_t - tag_directives_start int // The beginning of the tag directives list. - tag_directives_end int // The end of the tag directives list. - - start_implicit int // Is the document start indicator implicit? - end_implicit int // Is the document end indicator implicit? - - // The start/end of the document. - start_mark, end_mark yaml_mark_t -} - -// The prototype of a read handler. -// -// The read handler is called when the parser needs to read more bytes from the -// source. The handler should write not more than size bytes to the buffer. -// The number of written bytes should be set to the size_read variable. -// -// [in,out] data A pointer to an application data specified by -// yaml_parser_set_input(). -// [out] buffer The buffer to write the data from the source. -// [in] size The size of the buffer. -// [out] size_read The actual number of bytes read from the source. -// -// On success, the handler should return 1. If the handler failed, -// the returned value should be 0. On EOF, the handler should set the -// size_read to 0 and return 1. -type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) - -// This structure holds information about a potential simple key. -type yaml_simple_key_t struct { - possible bool // Is a simple key possible? - required bool // Is a simple key required? - token_number int // The number of the token. - mark yaml_mark_t // The position mark. -} - -// The states of the parser. -type yaml_parser_state_t int - -const ( - yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota - - yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. - yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. - yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. - yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. - yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. - yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. - yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. - yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. - yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. - yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. - yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. - yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. - yaml_PARSE_END_STATE // Expect nothing. -) - -func (ps yaml_parser_state_t) String() string { - switch ps { - case yaml_PARSE_STREAM_START_STATE: - return "yaml_PARSE_STREAM_START_STATE" - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_START_STATE: - return "yaml_PARSE_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return "yaml_PARSE_DOCUMENT_CONTENT_STATE" - case yaml_PARSE_DOCUMENT_END_STATE: - return "yaml_PARSE_DOCUMENT_END_STATE" - case yaml_PARSE_BLOCK_NODE_STATE: - return "yaml_PARSE_BLOCK_NODE_STATE" - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" - case yaml_PARSE_FLOW_NODE_STATE: - return "yaml_PARSE_FLOW_NODE_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" - case yaml_PARSE_END_STATE: - return "yaml_PARSE_END_STATE" - } - return "" -} - -// This structure holds aliases data. -type yaml_alias_data_t struct { - anchor []byte // The anchor. - index int // The node id. - mark yaml_mark_t // The anchor mark. -} - -// The parser structure. -// -// All members are internal. Manage the structure using the -// yaml_parser_ family of functions. -type yaml_parser_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - - problem string // Error description. - - // The byte about which the problem occurred. - problem_offset int - problem_value int - problem_mark yaml_mark_t - - // The error context. - context string - context_mark yaml_mark_t - - // Reader stuff - - read_handler yaml_read_handler_t // Read handler. - - input_reader io.Reader // File input data. - input []byte // String input data. - input_pos int - - eof bool // EOF flag - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - unread int // The number of unread characters in the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The input encoding. - - offset int // The offset of the current position (in bytes). - mark yaml_mark_t // The mark of the current position. - - // Scanner stuff - - stream_start_produced bool // Have we started to scan the input stream? - stream_end_produced bool // Have we reached the end of the input stream? - - flow_level int // The number of unclosed '[' and '{' indicators. - - tokens []yaml_token_t // The tokens queue. - tokens_head int // The head of the tokens queue. - tokens_parsed int // The number of tokens fetched from the queue. - token_available bool // Does the tokens queue contain a token ready for dequeueing. - - indent int // The current indentation level. - indents []int // The indentation levels stack. - - simple_key_allowed bool // May a simple key occur at the current position? - simple_keys []yaml_simple_key_t // The stack of simple keys. - simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number - - // Parser stuff - - state yaml_parser_state_t // The current parser state. - states []yaml_parser_state_t // The parser states stack. - marks []yaml_mark_t // The stack of marks. - tag_directives []yaml_tag_directive_t // The list of TAG directives. - - // Dumper stuff - - aliases []yaml_alias_data_t // The alias data. - - document *yaml_document_t // The currently parsed document. -} - -// Emitter Definitions - -// The prototype of a write handler. -// -// The write handler is called when the emitter needs to flush the accumulated -// characters to the output. The handler should write @a size bytes of the -// @a buffer to the output. -// -// @param[in,out] data A pointer to an application data specified by -// yaml_emitter_set_output(). -// @param[in] buffer The buffer with bytes to be written. -// @param[in] size The size of the buffer. -// -// @returns On success, the handler should return @c 1. If the handler failed, -// the returned value should be @c 0. -// -type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error - -type yaml_emitter_state_t int - -// The emitter states. -const ( - // Expect STREAM-START. - yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota - - yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. - yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. - yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. - yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. - yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. - yaml_EMIT_END_STATE // Expect nothing. -) - -// The emitter structure. -// -// All members are internal. Manage the structure using the @c yaml_emitter_ -// family of functions. -type yaml_emitter_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - problem string // Error description. - - // Writer stuff - - write_handler yaml_write_handler_t // Write handler. - - output_buffer *[]byte // String output data. - output_writer io.Writer // File output data. - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The stream encoding. - - // Emitter stuff - - canonical bool // If the output is in the canonical style? - best_indent int // The number of indentation spaces. - best_width int // The preferred width of the output lines. - unicode bool // Allow unescaped non-ASCII characters? - line_break yaml_break_t // The preferred line break. - - state yaml_emitter_state_t // The current emitter state. - states []yaml_emitter_state_t // The stack of states. - - events []yaml_event_t // The event queue. - events_head int // The head of the event queue. - - indents []int // The stack of indentation levels. - - tag_directives []yaml_tag_directive_t // The list of tag directives. - - indent int // The current indentation level. - - flow_level int // The current flow level. - - root_context bool // Is it the document root context? - sequence_context bool // Is it a sequence context? - mapping_context bool // Is it a mapping context? - simple_key_context bool // Is it a simple mapping key context? - - line int // The current line. - column int // The current column. - whitespace bool // If the last character was a whitespace? - indention bool // If the last character was an indentation character (' ', '-', '?', ':')? - open_ended bool // If an explicit document end is required? - - // Anchor analysis. - anchor_data struct { - anchor []byte // The anchor value. - alias bool // Is it an alias? - } - - // Tag analysis. - tag_data struct { - handle []byte // The tag handle. - suffix []byte // The tag suffix. - } - - // Scalar analysis. - scalar_data struct { - value []byte // The scalar value. - multiline bool // Does the scalar contain line breaks? - flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? - block_plain_allowed bool // Can the scalar be expressed in the block plain style? - single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? - block_allowed bool // Can the scalar be expressed in the literal or folded styles? - style yaml_scalar_style_t // The output style. - } - - // Dumper stuff - - opened bool // If the stream was already opened? - closed bool // If the stream was already closed? - - // The information associated with the document nodes. - anchors *struct { - references int // The number of references. - anchor int // The anchor id. - serialized bool // If the node has been emitted? - } - - last_anchor_id int // The last assigned anchor id. - - document *yaml_document_t // The currently emitted document. -} diff --git a/vendor/sigs.k8s.io/yaml/goyaml.v2/yamlprivateh.go b/vendor/sigs.k8s.io/yaml/goyaml.v2/yamlprivateh.go deleted file mode 100644 index 8110ce3c37..0000000000 --- a/vendor/sigs.k8s.io/yaml/goyaml.v2/yamlprivateh.go +++ /dev/null @@ -1,173 +0,0 @@ -package yaml - -const ( - // The size of the input raw buffer. - input_raw_buffer_size = 512 - - // The size of the input buffer. - // It should be possible to decode the whole raw buffer. - input_buffer_size = input_raw_buffer_size * 3 - - // The size of the output buffer. - output_buffer_size = 128 - - // The size of the output raw buffer. - // It should be possible to encode the whole output buffer. - output_raw_buffer_size = (output_buffer_size*2 + 2) - - // The size of other stacks and queues. - initial_stack_size = 16 - initial_queue_size = 16 - initial_string_size = 16 -) - -// Check if the character at the specified position is an alphabetical -// character, a digit, '_', or '-'. -func is_alpha(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' -} - -// Check if the character at the specified position is a digit. -func is_digit(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' -} - -// Get the value of a digit. -func as_digit(b []byte, i int) int { - return int(b[i]) - '0' -} - -// Check if the character at the specified position is a hex-digit. -func is_hex(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' -} - -// Get the value of a hex-digit. -func as_hex(b []byte, i int) int { - bi := b[i] - if bi >= 'A' && bi <= 'F' { - return int(bi) - 'A' + 10 - } - if bi >= 'a' && bi <= 'f' { - return int(bi) - 'a' + 10 - } - return int(bi) - '0' -} - -// Check if the character is ASCII. -func is_ascii(b []byte, i int) bool { - return b[i] <= 0x7F -} - -// Check if the character at the start of the buffer can be printed unescaped. -func is_printable(b []byte, i int) bool { - return ((b[i] == 0x0A) || // . == #x0A - (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E - (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF - (b[i] > 0xC2 && b[i] < 0xED) || - (b[i] == 0xED && b[i+1] < 0xA0) || - (b[i] == 0xEE) || - (b[i] == 0xEF && // #xE000 <= . <= #xFFFD - !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF - !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) -} - -// Check if the character at the specified position is NUL. -func is_z(b []byte, i int) bool { - return b[i] == 0x00 -} - -// Check if the beginning of the buffer is a BOM. -func is_bom(b []byte, i int) bool { - return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF -} - -// Check if the character at the specified position is space. -func is_space(b []byte, i int) bool { - return b[i] == ' ' -} - -// Check if the character at the specified position is tab. -func is_tab(b []byte, i int) bool { - return b[i] == '\t' -} - -// Check if the character at the specified position is blank (space or tab). -func is_blank(b []byte, i int) bool { - //return is_space(b, i) || is_tab(b, i) - return b[i] == ' ' || b[i] == '\t' -} - -// Check if the character at the specified position is a line break. -func is_break(b []byte, i int) bool { - return (b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) -} - -func is_crlf(b []byte, i int) bool { - return b[i] == '\r' && b[i+1] == '\n' -} - -// Check if the character is a line break or NUL. -func is_breakz(b []byte, i int) bool { - //return is_break(b, i) || is_z(b, i) - return ( // is_break: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - // is_z: - b[i] == 0) -} - -// Check if the character is a line break, space, or NUL. -func is_spacez(b []byte, i int) bool { - //return is_space(b, i) || is_breakz(b, i) - return ( // is_space: - b[i] == ' ' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Check if the character is a line break, space, tab, or NUL. -func is_blankz(b []byte, i int) bool { - //return is_blank(b, i) || is_breakz(b, i) - return ( // is_blank: - b[i] == ' ' || b[i] == '\t' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Determine the width of the character. -func width(b byte) int { - // Don't replace these by a switch without first - // confirming that it is being inlined. - if b&0x80 == 0x00 { - return 1 - } - if b&0xE0 == 0xC0 { - return 2 - } - if b&0xF0 == 0xE0 { - return 3 - } - if b&0xF8 == 0xF0 { - return 4 - } - return 0 - -} diff --git a/vendor/sigs.k8s.io/yaml/yaml.go b/vendor/sigs.k8s.io/yaml/yaml.go index fc10246bdb..aa01acd45d 100644 --- a/vendor/sigs.k8s.io/yaml/yaml.go +++ b/vendor/sigs.k8s.io/yaml/yaml.go @@ -24,7 +24,7 @@ import ( "reflect" "strconv" - "sigs.k8s.io/yaml/goyaml.v2" + "go.yaml.in/yaml/v2" ) // Marshal marshals obj into JSON using stdlib json.Marshal, and then converts JSON to YAML using JSONToYAML (see that method for more reference) @@ -92,7 +92,7 @@ func jsonUnmarshal(reader io.Reader, obj interface{}, opts ...JSONOpt) error { d = opt(d) } if err := d.Decode(&obj); err != nil { - return fmt.Errorf("while decoding JSON: %v", err) + return fmt.Errorf("while decoding JSON: %w", err) } return nil } @@ -417,3 +417,10 @@ func jsonToYAMLValue(j interface{}) interface{} { } return j } + +// DisallowUnknownFields configures the JSON decoder to error out if unknown +// fields come along, instead of dropping them by default. +func DisallowUnknownFields(d *json.Decoder) *json.Decoder { + d.DisallowUnknownFields() + return d +} diff --git a/vendor/sigs.k8s.io/yaml/yaml_go110.go b/vendor/sigs.k8s.io/yaml/yaml_go110.go deleted file mode 100644 index 94abc1719d..0000000000 --- a/vendor/sigs.k8s.io/yaml/yaml_go110.go +++ /dev/null @@ -1,31 +0,0 @@ -// This file contains changes that are only compatible with go 1.10 and onwards. - -//go:build go1.10 -// +build go1.10 - -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package yaml - -import "encoding/json" - -// DisallowUnknownFields configures the JSON decoder to error out if unknown -// fields come along, instead of dropping them by default. -func DisallowUnknownFields(d *json.Decoder) *json.Decoder { - d.DisallowUnknownFields() - return d -}