From 0899d6a13619cba03bc0c933ef0c7032c2393311 Mon Sep 17 00:00:00 2001 From: emmanuel Date: Sat, 5 Feb 2022 15:39:29 +0000 Subject: [PATCH] CC-796: Remove dependency on unsupported version of go-oidc --- go.mod | 6 +- go.sum | 10 +- sshgen/sshgen.go | 18 +- sshgen/sshgen_test.go | 36 +- token/token.go | 17 +- vendor/github.com/coreos/go-oidc/LICENSE | 202 ----------- vendor/github.com/coreos/go-oidc/NOTICE | 5 - .../github.com/coreos/go-oidc/jose/claims.go | 126 ------- vendor/github.com/coreos/go-oidc/jose/doc.go | 2 - vendor/github.com/coreos/go-oidc/jose/jose.go | 112 ------ vendor/github.com/coreos/go-oidc/jose/jwk.go | 135 ------- vendor/github.com/coreos/go-oidc/jose/jws.go | 51 --- vendor/github.com/coreos/go-oidc/jose/jwt.go | 82 ----- vendor/github.com/coreos/go-oidc/jose/sig.go | 24 -- .../github.com/coreos/go-oidc/jose/sig_rsa.go | 67 ---- vendor/gopkg.in/coreos/go-oidc.v2/.travis.yml | 6 +- vendor/gopkg.in/coreos/go-oidc.v2/oidc.go | 34 +- vendor/gopkg.in/coreos/go-oidc.v2/verify.go | 11 +- vendor/gopkg.in/square/go-jose.v2/.gitignore | 1 + vendor/gopkg.in/square/go-jose.v2/.travis.yml | 9 +- .../square/go-jose.v2/cipher/cbc_hmac.go | 2 +- vendor/gopkg.in/square/go-jose.v2/crypter.go | 1 + vendor/gopkg.in/square/go-jose.v2/encoding.go | 14 +- .../gopkg.in/square/go-jose.v2/json/decode.go | 52 ++- .../gopkg.in/square/go-jose.v2/json/stream.go | 7 +- vendor/gopkg.in/square/go-jose.v2/jwk.go | 174 ++++++++- vendor/gopkg.in/square/go-jose.v2/jws.go | 6 +- .../gopkg.in/square/go-jose.v2/jwt/builder.go | 334 ++++++++++++++++++ .../gopkg.in/square/go-jose.v2/jwt/claims.go | 121 +++++++ vendor/gopkg.in/square/go-jose.v2/jwt/doc.go | 22 ++ .../gopkg.in/square/go-jose.v2/jwt/errors.go | 53 +++ vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go | 169 +++++++++ .../square/go-jose.v2/jwt/validation.go | 114 ++++++ vendor/gopkg.in/square/go-jose.v2/opaque.go | 2 +- vendor/gopkg.in/square/go-jose.v2/shared.go | 6 +- vendor/gopkg.in/square/go-jose.v2/signing.go | 12 +- vendor/modules.txt | 8 +- 37 files changed, 1146 insertions(+), 905 deletions(-) delete mode 100644 vendor/github.com/coreos/go-oidc/LICENSE delete mode 100644 vendor/github.com/coreos/go-oidc/NOTICE delete mode 100644 vendor/github.com/coreos/go-oidc/jose/claims.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/doc.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/jose.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/jwk.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/jws.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/jwt.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/sig.go delete mode 100644 vendor/github.com/coreos/go-oidc/jose/sig_rsa.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwt/builder.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwt/claims.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwt/doc.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwt/errors.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwt/validation.go diff --git a/go.mod b/go.mod index 59b8ec7c..83328b33 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93 github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc github.com/coredns/coredns v1.8.7 - github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect @@ -51,14 +50,15 @@ require ( golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb // indirect google.golang.org/grpc v1.43.0 // indirect - gopkg.in/coreos/go-oidc.v2 v2.1.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 - gopkg.in/square/go-jose.v2 v2.4.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect zombiezen.com/go/capnproto2 v2.18.0+incompatible ) +require gopkg.in/coreos/go-oidc.v2 v2.2.1 + require ( github.com/BurntSushi/toml v0.3.1 // indirect github.com/apparentlymart/go-cidr v1.1.0 // indirect diff --git a/go.sum b/go.sum index ed534dcb..44c59257 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,6 @@ github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/coredns v1.8.7 h1:wVMjAnyFnY7Mc18AFO+9qbGD6ODPtdVUIlzoWrHr3hk= github.com/coredns/coredns v1.8.7/go.mod h1:bFmbgEfeRz5aizL2VsQ5LRlsvJuXWkgG/MWG9zxqjVM= -github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73 h1:7CNPV0LWRCa1FNmqg700pbXhzvmoaXKyfxWRkjRym7Q= -github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -1052,15 +1050,15 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/coreos/go-oidc.v2 v2.1.0 h1:E8PjVFdj/SLDKB0hvb70KTbMbYVHjqztiQdSkIg8E+I= -gopkg.in/coreos/go-oidc.v2 v2.1.0/go.mod h1:fYaTe2FS96wZZwR17YTDHwG+Mw6fmyqJNxN2eNCGPCI= +gopkg.in/coreos/go-oidc.v2 v2.2.1 h1:MY5SZClJ7vhjKfr64a4nHAOV/c3WH2gB9BMrR64J1Mc= +gopkg.in/coreos/go-oidc.v2 v2.2.1/go.mod h1:fYaTe2FS96wZZwR17YTDHwG+Mw6fmyqJNxN2eNCGPCI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/square/go-jose.v2 v2.4.0 h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A= -gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/sshgen/sshgen.go b/sshgen/sshgen.go index 9fba2053..27e73715 100644 --- a/sshgen/sshgen.go +++ b/sshgen/sshgen.go @@ -15,10 +15,10 @@ import ( "net/url" "time" - "github.com/coreos/go-oidc/jose" homedir "github.com/mitchellh/go-homedir" "github.com/pkg/errors" gossh "golang.org/x/crypto/ssh" + "gopkg.in/square/go-jose.v2/jwt" "github.com/cloudflare/cloudflared/config" cfpath "github.com/cloudflare/cloudflared/token" @@ -87,37 +87,33 @@ func SignCert(token, pubKey string) (string, error) { return "", errors.New("invalid token") } - jwt, err := jose.ParseJWT(token) + parsedToken, err := jwt.ParseSigned(token) if err != nil { return "", errors.Wrap(err, "failed to parse JWT") } - claims, err := jwt.Claims() + claims := jwt.Claims{} + err = parsedToken.UnsafeClaimsWithoutVerification(&claims) if err != nil { return "", errors.Wrap(err, "failed to retrieve JWT claims") } - issuer, _, err := claims.StringClaim("iss") - if err != nil { - return "", errors.Wrap(err, "failed to retrieve JWT iss") - } - buf, err := json.Marshal(&signPayload{ PublicKey: pubKey, JWT: token, - Issuer: issuer, + Issuer: claims.Issuer, }) if err != nil { return "", errors.Wrap(err, "failed to marshal signPayload") } var res *http.Response if mockRequest != nil { - res, err = mockRequest(issuer+signEndpoint, "application/json", bytes.NewBuffer(buf)) + res, err = mockRequest(claims.Issuer+signEndpoint, "application/json", bytes.NewBuffer(buf)) } else { client := http.Client{ Timeout: 10 * time.Second, } - res, err = client.Post(issuer+signEndpoint, "application/json", bytes.NewBuffer(buf)) + res, err = client.Post(claims.Issuer+signEndpoint, "application/json", bytes.NewBuffer(buf)) } if err != nil { diff --git a/sshgen/sshgen_test.go b/sshgen/sshgen_test.go index 99ac8021..c2716f59 100644 --- a/sshgen/sshgen_test.go +++ b/sshgen/sshgen_test.go @@ -4,8 +4,6 @@ package sshgen import ( - "crypto/rand" - "crypto/rsa" "encoding/json" "fmt" "io" @@ -18,8 +16,9 @@ import ( "testing" "time" - "github.com/coreos/go-oidc/jose" "github.com/stretchr/testify/assert" + "gopkg.in/square/go-jose.v2" + "gopkg.in/square/go-jose.v2/jwt" "github.com/cloudflare/cloudflared/config" cfpath "github.com/cloudflare/cloudflared/token" @@ -97,22 +96,25 @@ func TestCertGenSuccess(t *testing.T) { } func tokenGenerator() string { - iat := time.Now().Unix() - exp := time.Now().Add(time.Minute * 5).Unix() - claims := jose.Claims{} - claims.Add("aud", audTest) - claims.Add("iat", iat) - claims.Add("nonce", nonceTest) - claims.Add("exp", exp) + iat := time.Now() + exp := time.Now().Add(time.Minute * 5) - k, err := rsa.GenerateKey(rand.Reader, 512) + claims := jwt.Claims{ + Audience: jwt.Audience{audTest}, + IssuedAt: jwt.NewNumericDate(iat), + Expiry: jwt.NewNumericDate(exp), + } + + key := []byte("secret") + signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT")) if err != nil { - return "" + panic(err) } - signer := jose.NewSignerRSA("asdf", *k) - token, terr := jose.NewSignedJWT(claims, signer) - if terr != nil { - return "" + + signedToken, err := jwt.Signed(signer).Claims(claims).CompactSerialize() + if err != nil { + panic(err) } - return token.Encode() + + return signedToken } diff --git a/token/token.go b/token/token.go index d4f237a9..abccf257 100644 --- a/token/token.go +++ b/token/token.go @@ -13,9 +13,9 @@ import ( "syscall" "time" - "github.com/coreos/go-oidc/jose" "github.com/pkg/errors" "github.com/rs/zerolog" + "gopkg.in/square/go-jose.v2" "github.com/cloudflare/cloudflared/config" "github.com/cloudflare/cloudflared/retry" @@ -342,7 +342,7 @@ func GetOrgTokenIfExists(authDomain string) (string, error) { return "", err } var payload jwtPayload - err = json.Unmarshal(token.Payload, &payload) + err = json.Unmarshal(token.UnsafePayloadWithoutVerification(), &payload) if err != nil { return "", err } @@ -351,7 +351,7 @@ func GetOrgTokenIfExists(authDomain string) (string, error) { err := os.Remove(path) return "", err } - return token.Encode(), nil + return token.CompactSerialize() } func GetAppTokenIfExists(appInfo *AppInfo) (string, error) { @@ -364,7 +364,7 @@ func GetAppTokenIfExists(appInfo *AppInfo) (string, error) { return "", err } var payload jwtPayload - err = json.Unmarshal(token.Payload, &payload) + err = json.Unmarshal(token.UnsafePayloadWithoutVerification(), &payload) if err != nil { return "", err } @@ -373,22 +373,21 @@ func GetAppTokenIfExists(appInfo *AppInfo) (string, error) { err := os.Remove(path) return "", err } - return token.Encode(), nil + return token.CompactSerialize() } // GetTokenIfExists will return the token from local storage if it exists and not expired -func getTokenIfExists(path string) (*jose.JWT, error) { +func getTokenIfExists(path string) (*jose.JSONWebSignature, error) { content, err := ioutil.ReadFile(path) if err != nil { return nil, err } - token, err := jose.ParseJWT(string(content)) + token, err := jose.ParseSigned(string(content)) if err != nil { return nil, err } - - return &token, nil + return token, nil } // RemoveTokenIfExists removes the a token from local storage if it exists diff --git a/vendor/github.com/coreos/go-oidc/LICENSE b/vendor/github.com/coreos/go-oidc/LICENSE deleted file mode 100644 index e06d2081..00000000 --- a/vendor/github.com/coreos/go-oidc/LICENSE +++ /dev/null @@ -1,202 +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/github.com/coreos/go-oidc/NOTICE b/vendor/github.com/coreos/go-oidc/NOTICE deleted file mode 100644 index b39ddfa5..00000000 --- a/vendor/github.com/coreos/go-oidc/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -CoreOS Project -Copyright 2014 CoreOS, Inc - -This product includes software developed at CoreOS, Inc. -(http://www.coreos.com/). diff --git a/vendor/github.com/coreos/go-oidc/jose/claims.go b/vendor/github.com/coreos/go-oidc/jose/claims.go deleted file mode 100644 index 8b48bfd2..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/claims.go +++ /dev/null @@ -1,126 +0,0 @@ -package jose - -import ( - "encoding/json" - "fmt" - "math" - "time" -) - -type Claims map[string]interface{} - -func (c Claims) Add(name string, value interface{}) { - c[name] = value -} - -func (c Claims) StringClaim(name string) (string, bool, error) { - cl, ok := c[name] - if !ok { - return "", false, nil - } - - v, ok := cl.(string) - if !ok { - return "", false, fmt.Errorf("unable to parse claim as string: %v", name) - } - - return v, true, nil -} - -func (c Claims) StringsClaim(name string) ([]string, bool, error) { - cl, ok := c[name] - if !ok { - return nil, false, nil - } - - if v, ok := cl.([]string); ok { - return v, true, nil - } - - // When unmarshaled, []string will become []interface{}. - if v, ok := cl.([]interface{}); ok { - var ret []string - for _, vv := range v { - str, ok := vv.(string) - if !ok { - return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name) - } - ret = append(ret, str) - } - return ret, true, nil - } - - return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name) -} - -func (c Claims) Int64Claim(name string) (int64, bool, error) { - cl, ok := c[name] - if !ok { - return 0, false, nil - } - - v, ok := cl.(int64) - if !ok { - vf, ok := cl.(float64) - if !ok { - return 0, false, fmt.Errorf("unable to parse claim as int64: %v", name) - } - v = int64(vf) - } - - return v, true, nil -} - -func (c Claims) Float64Claim(name string) (float64, bool, error) { - cl, ok := c[name] - if !ok { - return 0, false, nil - } - - v, ok := cl.(float64) - if !ok { - vi, ok := cl.(int64) - if !ok { - return 0, false, fmt.Errorf("unable to parse claim as float64: %v", name) - } - v = float64(vi) - } - - return v, true, nil -} - -func (c Claims) TimeClaim(name string) (time.Time, bool, error) { - v, ok, err := c.Float64Claim(name) - if !ok || err != nil { - return time.Time{}, ok, err - } - - s := math.Trunc(v) - ns := (v - s) * math.Pow(10, 9) - return time.Unix(int64(s), int64(ns)).UTC(), true, nil -} - -func decodeClaims(payload []byte) (Claims, error) { - var c Claims - if err := json.Unmarshal(payload, &c); err != nil { - return nil, fmt.Errorf("malformed JWT claims, unable to decode: %v", err) - } - return c, nil -} - -func marshalClaims(c Claims) ([]byte, error) { - b, err := json.Marshal(c) - if err != nil { - return nil, err - } - return b, nil -} - -func encodeClaims(c Claims) (string, error) { - b, err := marshalClaims(c) - if err != nil { - return "", err - } - - return encodeSegment(b), nil -} diff --git a/vendor/github.com/coreos/go-oidc/jose/doc.go b/vendor/github.com/coreos/go-oidc/jose/doc.go deleted file mode 100644 index b5e13217..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package jose is DEPRECATED. Use gopkg.in/square/go-jose.v2 instead. -package jose diff --git a/vendor/github.com/coreos/go-oidc/jose/jose.go b/vendor/github.com/coreos/go-oidc/jose/jose.go deleted file mode 100644 index 62099265..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/jose.go +++ /dev/null @@ -1,112 +0,0 @@ -package jose - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "strings" -) - -const ( - HeaderMediaType = "typ" - HeaderKeyAlgorithm = "alg" - HeaderKeyID = "kid" -) - -const ( - // Encryption Algorithm Header Parameter Values for JWS - // See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-6 - AlgHS256 = "HS256" - AlgHS384 = "HS384" - AlgHS512 = "HS512" - AlgRS256 = "RS256" - AlgRS384 = "RS384" - AlgRS512 = "RS512" - AlgES256 = "ES256" - AlgES384 = "ES384" - AlgES512 = "ES512" - AlgPS256 = "PS256" - AlgPS384 = "PS384" - AlgPS512 = "PS512" - AlgNone = "none" -) - -const ( - // Algorithm Header Parameter Values for JWE - // See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-4.1 - AlgRSA15 = "RSA1_5" - AlgRSAOAEP = "RSA-OAEP" - AlgRSAOAEP256 = "RSA-OAEP-256" - AlgA128KW = "A128KW" - AlgA192KW = "A192KW" - AlgA256KW = "A256KW" - AlgDir = "dir" - AlgECDHES = "ECDH-ES" - AlgECDHESA128KW = "ECDH-ES+A128KW" - AlgECDHESA192KW = "ECDH-ES+A192KW" - AlgECDHESA256KW = "ECDH-ES+A256KW" - AlgA128GCMKW = "A128GCMKW" - AlgA192GCMKW = "A192GCMKW" - AlgA256GCMKW = "A256GCMKW" - AlgPBES2HS256A128KW = "PBES2-HS256+A128KW" - AlgPBES2HS384A192KW = "PBES2-HS384+A192KW" - AlgPBES2HS512A256KW = "PBES2-HS512+A256KW" -) - -const ( - // Encryption Algorithm Header Parameter Values for JWE - // See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-22 - EncA128CBCHS256 = "A128CBC-HS256" - EncA128CBCHS384 = "A128CBC-HS384" - EncA256CBCHS512 = "A256CBC-HS512" - EncA128GCM = "A128GCM" - EncA192GCM = "A192GCM" - EncA256GCM = "A256GCM" -) - -type JOSEHeader map[string]string - -func (j JOSEHeader) Validate() error { - if _, exists := j[HeaderKeyAlgorithm]; !exists { - return fmt.Errorf("header missing %q parameter", HeaderKeyAlgorithm) - } - - return nil -} - -func decodeHeader(seg string) (JOSEHeader, error) { - b, err := decodeSegment(seg) - if err != nil { - return nil, err - } - - var h JOSEHeader - err = json.Unmarshal(b, &h) - if err != nil { - return nil, err - } - - return h, nil -} - -func encodeHeader(h JOSEHeader) (string, error) { - b, err := json.Marshal(h) - if err != nil { - return "", err - } - - return encodeSegment(b), nil -} - -// Decode JWT specific base64url encoding with padding stripped -func decodeSegment(seg string) ([]byte, error) { - if l := len(seg) % 4; l != 0 { - seg += strings.Repeat("=", 4-l) - } - return base64.URLEncoding.DecodeString(seg) -} - -// Encode JWT specific base64url encoding with padding stripped -func encodeSegment(seg []byte) string { - return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") -} diff --git a/vendor/github.com/coreos/go-oidc/jose/jwk.go b/vendor/github.com/coreos/go-oidc/jose/jwk.go deleted file mode 100644 index 119f073f..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/jwk.go +++ /dev/null @@ -1,135 +0,0 @@ -package jose - -import ( - "bytes" - "encoding/base64" - "encoding/binary" - "encoding/json" - "math/big" - "strings" -) - -// JSON Web Key -// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-36#page-5 -type JWK struct { - ID string - Type string - Alg string - Use string - Exponent int - Modulus *big.Int - Secret []byte -} - -type jwkJSON struct { - ID string `json:"kid"` - Type string `json:"kty"` - Alg string `json:"alg"` - Use string `json:"use"` - Exponent string `json:"e"` - Modulus string `json:"n"` -} - -func (j *JWK) MarshalJSON() ([]byte, error) { - t := jwkJSON{ - ID: j.ID, - Type: j.Type, - Alg: j.Alg, - Use: j.Use, - Exponent: encodeExponent(j.Exponent), - Modulus: encodeModulus(j.Modulus), - } - - return json.Marshal(&t) -} - -func (j *JWK) UnmarshalJSON(data []byte) error { - var t jwkJSON - err := json.Unmarshal(data, &t) - if err != nil { - return err - } - - e, err := decodeExponent(t.Exponent) - if err != nil { - return err - } - - n, err := decodeModulus(t.Modulus) - if err != nil { - return err - } - - j.ID = t.ID - j.Type = t.Type - j.Alg = t.Alg - j.Use = t.Use - j.Exponent = e - j.Modulus = n - - return nil -} - -type JWKSet struct { - Keys []JWK `json:"keys"` -} - -func decodeExponent(e string) (int, error) { - decE, err := decodeBase64URLPaddingOptional(e) - if err != nil { - return 0, err - } - var eBytes []byte - if len(decE) < 8 { - eBytes = make([]byte, 8-len(decE), 8) - eBytes = append(eBytes, decE...) - } else { - eBytes = decE - } - eReader := bytes.NewReader(eBytes) - var E uint64 - err = binary.Read(eReader, binary.BigEndian, &E) - if err != nil { - return 0, err - } - return int(E), nil -} - -func encodeExponent(e int) string { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(e)) - var idx int - for ; idx < 8; idx++ { - if b[idx] != 0x0 { - break - } - } - return base64.RawURLEncoding.EncodeToString(b[idx:]) -} - -// Turns a URL encoded modulus of a key into a big int. -func decodeModulus(n string) (*big.Int, error) { - decN, err := decodeBase64URLPaddingOptional(n) - if err != nil { - return nil, err - } - N := big.NewInt(0) - N.SetBytes(decN) - return N, nil -} - -func encodeModulus(n *big.Int) string { - return base64.RawURLEncoding.EncodeToString(n.Bytes()) -} - -// decodeBase64URLPaddingOptional decodes Base64 whether there is padding or not. -// The stdlib version currently doesn't handle this. -// We can get rid of this is if this bug: -// https://github.com/golang/go/issues/4237 -// ever closes. -func decodeBase64URLPaddingOptional(e string) ([]byte, error) { - if m := len(e) % 4; m != 0 { - e += strings.Repeat("=", 4-m) - } - return base64.URLEncoding.DecodeString(e) -} diff --git a/vendor/github.com/coreos/go-oidc/jose/jws.go b/vendor/github.com/coreos/go-oidc/jose/jws.go deleted file mode 100644 index 1049ece8..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/jws.go +++ /dev/null @@ -1,51 +0,0 @@ -package jose - -import ( - "fmt" - "strings" -) - -type JWS struct { - RawHeader string - Header JOSEHeader - RawPayload string - Payload []byte - Signature []byte -} - -// Given a raw encoded JWS token parses it and verifies the structure. -func ParseJWS(raw string) (JWS, error) { - parts := strings.Split(raw, ".") - if len(parts) != 3 { - return JWS{}, fmt.Errorf("malformed JWS, only %d segments", len(parts)) - } - - rawSig := parts[2] - jws := JWS{ - RawHeader: parts[0], - RawPayload: parts[1], - } - - header, err := decodeHeader(jws.RawHeader) - if err != nil { - return JWS{}, fmt.Errorf("malformed JWS, unable to decode header, %s", err) - } - if err = header.Validate(); err != nil { - return JWS{}, fmt.Errorf("malformed JWS, %s", err) - } - jws.Header = header - - payload, err := decodeSegment(jws.RawPayload) - if err != nil { - return JWS{}, fmt.Errorf("malformed JWS, unable to decode payload: %s", err) - } - jws.Payload = payload - - sig, err := decodeSegment(rawSig) - if err != nil { - return JWS{}, fmt.Errorf("malformed JWS, unable to decode signature: %s", err) - } - jws.Signature = sig - - return jws, nil -} diff --git a/vendor/github.com/coreos/go-oidc/jose/jwt.go b/vendor/github.com/coreos/go-oidc/jose/jwt.go deleted file mode 100644 index 3b3e9634..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/jwt.go +++ /dev/null @@ -1,82 +0,0 @@ -package jose - -import "strings" - -type JWT JWS - -func ParseJWT(token string) (jwt JWT, err error) { - jws, err := ParseJWS(token) - if err != nil { - return - } - - return JWT(jws), nil -} - -func NewJWT(header JOSEHeader, claims Claims) (jwt JWT, err error) { - jwt = JWT{} - - jwt.Header = header - jwt.Header[HeaderMediaType] = "JWT" - - claimBytes, err := marshalClaims(claims) - if err != nil { - return - } - jwt.Payload = claimBytes - - eh, err := encodeHeader(header) - if err != nil { - return - } - jwt.RawHeader = eh - - ec, err := encodeClaims(claims) - if err != nil { - return - } - jwt.RawPayload = ec - - return -} - -func (j *JWT) KeyID() (string, bool) { - kID, ok := j.Header[HeaderKeyID] - return kID, ok -} - -func (j *JWT) Claims() (Claims, error) { - return decodeClaims(j.Payload) -} - -// Encoded data part of the token which may be signed. -func (j *JWT) Data() string { - return strings.Join([]string{j.RawHeader, j.RawPayload}, ".") -} - -// Full encoded JWT token string in format: header.claims.signature -func (j *JWT) Encode() string { - d := j.Data() - s := encodeSegment(j.Signature) - return strings.Join([]string{d, s}, ".") -} - -func NewSignedJWT(claims Claims, s Signer) (*JWT, error) { - header := JOSEHeader{ - HeaderKeyAlgorithm: s.Alg(), - HeaderKeyID: s.ID(), - } - - jwt, err := NewJWT(header, claims) - if err != nil { - return nil, err - } - - sig, err := s.Sign([]byte(jwt.Data())) - if err != nil { - return nil, err - } - jwt.Signature = sig - - return &jwt, nil -} diff --git a/vendor/github.com/coreos/go-oidc/jose/sig.go b/vendor/github.com/coreos/go-oidc/jose/sig.go deleted file mode 100644 index 7b2b253c..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/sig.go +++ /dev/null @@ -1,24 +0,0 @@ -package jose - -import ( - "fmt" -) - -type Verifier interface { - ID() string - Alg() string - Verify(sig []byte, data []byte) error -} - -type Signer interface { - Verifier - Sign(data []byte) (sig []byte, err error) -} - -func NewVerifier(jwk JWK) (Verifier, error) { - if jwk.Type != "RSA" { - return nil, fmt.Errorf("unsupported key type %q", jwk.Type) - } - - return NewVerifierRSA(jwk) -} diff --git a/vendor/github.com/coreos/go-oidc/jose/sig_rsa.go b/vendor/github.com/coreos/go-oidc/jose/sig_rsa.go deleted file mode 100644 index 004e45dd..00000000 --- a/vendor/github.com/coreos/go-oidc/jose/sig_rsa.go +++ /dev/null @@ -1,67 +0,0 @@ -package jose - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "fmt" -) - -type VerifierRSA struct { - KeyID string - Hash crypto.Hash - PublicKey rsa.PublicKey -} - -type SignerRSA struct { - PrivateKey rsa.PrivateKey - VerifierRSA -} - -func NewVerifierRSA(jwk JWK) (*VerifierRSA, error) { - if jwk.Alg != "" && jwk.Alg != "RS256" { - return nil, fmt.Errorf("unsupported key algorithm %q", jwk.Alg) - } - - v := VerifierRSA{ - KeyID: jwk.ID, - PublicKey: rsa.PublicKey{ - N: jwk.Modulus, - E: jwk.Exponent, - }, - Hash: crypto.SHA256, - } - - return &v, nil -} - -func NewSignerRSA(kid string, key rsa.PrivateKey) *SignerRSA { - return &SignerRSA{ - PrivateKey: key, - VerifierRSA: VerifierRSA{ - KeyID: kid, - PublicKey: key.PublicKey, - Hash: crypto.SHA256, - }, - } -} - -func (v *VerifierRSA) ID() string { - return v.KeyID -} - -func (v *VerifierRSA) Alg() string { - return "RS256" -} - -func (v *VerifierRSA) Verify(sig []byte, data []byte) error { - h := v.Hash.New() - h.Write(data) - return rsa.VerifyPKCS1v15(&v.PublicKey, v.Hash, h.Sum(nil), sig) -} - -func (s *SignerRSA) Sign(data []byte) ([]byte, error) { - h := s.Hash.New() - h.Write(data) - return rsa.SignPKCS1v15(rand.Reader, &s.PrivateKey, s.Hash, h.Sum(nil)) -} diff --git a/vendor/gopkg.in/coreos/go-oidc.v2/.travis.yml b/vendor/gopkg.in/coreos/go-oidc.v2/.travis.yml index 6ff9dd96..3fddaaac 100644 --- a/vendor/gopkg.in/coreos/go-oidc.v2/.travis.yml +++ b/vendor/gopkg.in/coreos/go-oidc.v2/.travis.yml @@ -1,13 +1,13 @@ language: go go: - - "1.9" - - "1.10" + - "1.12" + - "1.13" install: - go get -v -t github.com/coreos/go-oidc/... - go get golang.org/x/tools/cmd/cover - - go get github.com/golang/lint/golint + - go get golang.org/x/lint/golint script: - ./test diff --git a/vendor/gopkg.in/coreos/go-oidc.v2/oidc.go b/vendor/gopkg.in/coreos/go-oidc.v2/oidc.go index 508b39d3..b39cb515 100644 --- a/vendor/gopkg.in/coreos/go-oidc.v2/oidc.go +++ b/vendor/gopkg.in/coreos/go-oidc.v2/oidc.go @@ -69,6 +69,7 @@ type Provider struct { authURL string tokenURL string userInfoURL string + algorithms []string // Raw claims returned by the server. rawClaims []byte @@ -82,11 +83,27 @@ type cachedKeys struct { } type providerJSON struct { - Issuer string `json:"issuer"` - AuthURL string `json:"authorization_endpoint"` - TokenURL string `json:"token_endpoint"` - JWKSURL string `json:"jwks_uri"` - UserInfoURL string `json:"userinfo_endpoint"` + Issuer string `json:"issuer"` + AuthURL string `json:"authorization_endpoint"` + TokenURL string `json:"token_endpoint"` + JWKSURL string `json:"jwks_uri"` + UserInfoURL string `json:"userinfo_endpoint"` + Algorithms []string `json:"id_token_signing_alg_values_supported"` +} + +// supportedAlgorithms is a list of algorithms explicitly supported by this +// package. If a provider supports other algorithms, such as HS256 or none, +// those values won't be passed to the IDTokenVerifier. +var supportedAlgorithms = map[string]bool{ + RS256: true, + RS384: true, + RS512: true, + ES256: true, + ES384: true, + ES512: true, + PS256: true, + PS384: true, + PS512: true, } // NewProvider uses the OpenID Connect discovery mechanism to construct a Provider. @@ -123,11 +140,18 @@ func NewProvider(ctx context.Context, issuer string) (*Provider, error) { if p.Issuer != issuer { return nil, fmt.Errorf("oidc: issuer did not match the issuer returned by provider, expected %q got %q", issuer, p.Issuer) } + var algs []string + for _, a := range p.Algorithms { + if supportedAlgorithms[a] { + algs = append(algs, a) + } + } return &Provider{ issuer: p.Issuer, authURL: p.AuthURL, tokenURL: p.TokenURL, userInfoURL: p.UserInfoURL, + algorithms: algs, rawClaims: body, remoteKeySet: NewRemoteKeySet(ctx, p.JWKSURL), }, nil diff --git a/vendor/gopkg.in/coreos/go-oidc.v2/verify.go b/vendor/gopkg.in/coreos/go-oidc.v2/verify.go index ff7555db..d43f0662 100644 --- a/vendor/gopkg.in/coreos/go-oidc.v2/verify.go +++ b/vendor/gopkg.in/coreos/go-oidc.v2/verify.go @@ -79,7 +79,9 @@ type Config struct { ClientID string // If specified, only this set of algorithms may be used to sign the JWT. // - // Since many providers only support RS256, SupportedSigningAlgs defaults to this value. + // If the IDTokenVerifier is created from a provider with (*Provider).Verifier, this + // defaults to the set of algorithms the provider supports. Otherwise this values + // defaults to RS256. SupportedSigningAlgs []string // If true, no ClientID check performed. Must be true if ClientID field is empty. @@ -105,6 +107,13 @@ type Config struct { // The returned IDTokenVerifier is tied to the Provider's context and its behavior is // undefined once the Provider's context is canceled. func (p *Provider) Verifier(config *Config) *IDTokenVerifier { + if len(config.SupportedSigningAlgs) == 0 && len(p.algorithms) > 0 { + // Make a copy so we don't modify the config values. + cp := &Config{} + *cp = *config + cp.SupportedSigningAlgs = p.algorithms + config = cp + } return NewVerifier(p.issuer, p.remoteKeySet, config) } diff --git a/vendor/gopkg.in/square/go-jose.v2/.gitignore b/vendor/gopkg.in/square/go-jose.v2/.gitignore index 5b4d73b6..95a85158 100644 --- a/vendor/gopkg.in/square/go-jose.v2/.gitignore +++ b/vendor/gopkg.in/square/go-jose.v2/.gitignore @@ -5,3 +5,4 @@ *.pem *.cov jose-util/jose-util +jose-util.t.err \ No newline at end of file diff --git a/vendor/gopkg.in/square/go-jose.v2/.travis.yml b/vendor/gopkg.in/square/go-jose.v2/.travis.yml index 9ab2abf6..391b99a4 100644 --- a/vendor/gopkg.in/square/go-jose.v2/.travis.yml +++ b/vendor/gopkg.in/square/go-jose.v2/.travis.yml @@ -8,8 +8,8 @@ matrix: - go: tip go: -- '1.11.x' -- '1.12.x' +- '1.14.x' +- '1.15.x' - tip go_import_path: gopkg.in/square/go-jose.v2 @@ -26,6 +26,8 @@ before_install: - go get github.com/wadey/gocovmerge - go get github.com/mattn/goveralls - go get github.com/stretchr/testify/assert +- go get github.com/stretchr/testify/require +- go get github.com/google/go-cmp/cmp - go get golang.org/x/tools/cmd/cover || true - go get code.google.com/p/go.tools/cmd/cover || true - pip install cram --user @@ -35,10 +37,9 @@ script: - go test ./cipher -v -covermode=count -coverprofile=cipher/profile.cov - go test ./jwt -v -covermode=count -coverprofile=jwt/profile.cov - go test ./json -v # no coverage for forked encoding/json package -- cd jose-util && go build && PATH=$PWD:$PATH cram -v jose-util.t +- cd jose-util && go build && PATH=$PWD:$PATH cram -v jose-util.t # cram tests jose-util - cd .. after_success: - gocovmerge *.cov */*.cov > merged.coverprofile - $HOME/gopath/bin/goveralls -coverprofile merged.coverprofile -service=travis-ci - diff --git a/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go b/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go index 126b85ce..f6465c04 100644 --- a/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go +++ b/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go @@ -150,7 +150,7 @@ func (ctx *cbcAEAD) computeAuthTag(aad, nonce, ciphertext []byte) []byte { return hmac.Sum(nil)[:ctx.authtagBytes] } -// resize ensures the the given slice has a capacity of at least n bytes. +// resize ensures that the given slice has a capacity of at least n bytes. // If the capacity of the slice is less than n, a new slice is allocated // and the existing data will be copied. func resize(in []byte, n uint64) (head, tail []byte) { diff --git a/vendor/gopkg.in/square/go-jose.v2/crypter.go b/vendor/gopkg.in/square/go-jose.v2/crypter.go index d24cabf6..be7433e2 100644 --- a/vendor/gopkg.in/square/go-jose.v2/crypter.go +++ b/vendor/gopkg.in/square/go-jose.v2/crypter.go @@ -216,6 +216,7 @@ func NewMultiEncrypter(enc ContentEncryption, rcpts []Recipient, opts *Encrypter if opts != nil { encrypter.compressionAlg = opts.Compression + encrypter.extraHeaders = opts.ExtraHeaders } for _, recipient := range rcpts { diff --git a/vendor/gopkg.in/square/go-jose.v2/encoding.go b/vendor/gopkg.in/square/go-jose.v2/encoding.go index b9687c64..70f7385c 100644 --- a/vendor/gopkg.in/square/go-jose.v2/encoding.go +++ b/vendor/gopkg.in/square/go-jose.v2/encoding.go @@ -23,13 +23,12 @@ import ( "encoding/binary" "io" "math/big" - "regexp" + "strings" + "unicode" "gopkg.in/square/go-jose.v2/json" ) -var stripWhitespaceRegex = regexp.MustCompile("\\s") - // Helper function to serialize known-good objects. // Precondition: value is not a nil pointer. func mustSerializeJSON(value interface{}) []byte { @@ -56,7 +55,14 @@ func mustSerializeJSON(value interface{}) []byte { // Strip all newlines and whitespace func stripWhitespace(data string) string { - return stripWhitespaceRegex.ReplaceAllString(data, "") + buf := strings.Builder{} + buf.Grow(len(data)) + for _, r := range data { + if !unicode.IsSpace(r) { + buf.WriteRune(r) + } + } + return buf.String() } // Perform compression based on algorithm diff --git a/vendor/gopkg.in/square/go-jose.v2/json/decode.go b/vendor/gopkg.in/square/go-jose.v2/json/decode.go index 37457e5a..4dbc4146 100644 --- a/vendor/gopkg.in/square/go-jose.v2/json/decode.go +++ b/vendor/gopkg.in/square/go-jose.v2/json/decode.go @@ -13,6 +13,7 @@ import ( "encoding/base64" "errors" "fmt" + "math" "reflect" "runtime" "strconv" @@ -245,6 +246,18 @@ func isValidNumber(s string) bool { return s == "" } +type NumberUnmarshalType int + +const ( + // unmarshal a JSON number into an interface{} as a float64 + UnmarshalFloat NumberUnmarshalType = iota + // unmarshal a JSON number into an interface{} as a `json.Number` + UnmarshalJSONNumber + // unmarshal a JSON number into an interface{} as a int64 + // if value is an integer otherwise float64 + UnmarshalIntOrFloat +) + // decodeState represents the state while decoding a JSON value. type decodeState struct { data []byte @@ -252,7 +265,7 @@ type decodeState struct { scan scanner nextscan scanner // for calls to nextValue savedError error - useNumber bool + numberType NumberUnmarshalType } // errPhase is used for errors that should not happen unless @@ -723,17 +736,38 @@ func (d *decodeState) literal(v reflect.Value) { d.literalStore(d.data[start:d.off], v, false) } -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. +// convertNumber converts the number literal s to a float64, int64 or a Number +// depending on d.numberDecodeType. func (d *decodeState) convertNumber(s string) (interface{}, error) { - if d.useNumber { + switch d.numberType { + + case UnmarshalJSONNumber: return Number(s), nil + case UnmarshalIntOrFloat: + v, err := strconv.ParseInt(s, 10, 64) + if err == nil { + return v, nil + } + + // tries to parse integer number in scientific notation + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} + } + + // if it has no decimal value use int64 + if fi, fd := math.Modf(f); fd == 0.0 { + return int64(fi), nil + } + return f, nil + default: + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} + } + return f, nil } - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} - } - return f, nil + } var numberType = reflect.TypeOf(Number("")) diff --git a/vendor/gopkg.in/square/go-jose.v2/json/stream.go b/vendor/gopkg.in/square/go-jose.v2/json/stream.go index 8ddcf4d2..9b2b926b 100644 --- a/vendor/gopkg.in/square/go-jose.v2/json/stream.go +++ b/vendor/gopkg.in/square/go-jose.v2/json/stream.go @@ -31,9 +31,14 @@ func NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r} } +// Deprecated: Use `SetNumberType` instead // UseNumber causes the Decoder to unmarshal a number into an interface{} as a // Number instead of as a float64. -func (dec *Decoder) UseNumber() { dec.d.useNumber = true } +func (dec *Decoder) UseNumber() { dec.d.numberType = UnmarshalJSONNumber } + +// SetNumberType causes the Decoder to unmarshal a number into an interface{} as a +// Number, float64 or int64 depending on `t` enum value. +func (dec *Decoder) SetNumberType(t NumberUnmarshalType) { dec.d.numberType = t } // Decode reads the next JSON-encoded value from its // input and stores it in the value pointed to by v. diff --git a/vendor/gopkg.in/square/go-jose.v2/jwk.go b/vendor/gopkg.in/square/go-jose.v2/jwk.go index 936a0202..222e260c 100644 --- a/vendor/gopkg.in/square/go-jose.v2/jwk.go +++ b/vendor/gopkg.in/square/go-jose.v2/jwk.go @@ -17,15 +17,20 @@ package jose import ( + "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" + "crypto/sha1" + "crypto/sha256" "crypto/x509" "encoding/base64" + "encoding/hex" "errors" "fmt" "math/big" + "net/url" "reflect" "strings" @@ -57,16 +62,31 @@ type rawJSONWebKey struct { Dq *byteBuffer `json:"dq,omitempty"` Qi *byteBuffer `json:"qi,omitempty"` // Certificates - X5c []string `json:"x5c,omitempty"` + X5c []string `json:"x5c,omitempty"` + X5u *url.URL `json:"x5u,omitempty"` + X5tSHA1 string `json:"x5t,omitempty"` + X5tSHA256 string `json:"x5t#S256,omitempty"` } // JSONWebKey represents a public or private key in JWK format. type JSONWebKey struct { - Key interface{} + // Cryptographic key, can be a symmetric or asymmetric key. + Key interface{} + // Key identifier, parsed from `kid` header. + KeyID string + // Key algorithm, parsed from `alg` header. + Algorithm string + // Key use, parsed from `use` header. + Use string + + // X.509 certificate chain, parsed from `x5c` header. Certificates []*x509.Certificate - KeyID string - Algorithm string - Use string + // X.509 certificate URL, parsed from `x5u` header. + CertificatesURL *url.URL + // X.509 certificate thumbprint (SHA-1), parsed from `x5t` header. + CertificateThumbprintSHA1 []byte + // X.509 certificate thumbprint (SHA-256), parsed from `x5t#S256` header. + CertificateThumbprintSHA256 []byte } // MarshalJSON serializes the given key to its JSON representation. @@ -105,6 +125,39 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) { raw.X5c = append(raw.X5c, base64.StdEncoding.EncodeToString(cert.Raw)) } + x5tSHA1Len := len(k.CertificateThumbprintSHA1) + x5tSHA256Len := len(k.CertificateThumbprintSHA256) + if x5tSHA1Len > 0 { + if x5tSHA1Len != sha1.Size { + return nil, fmt.Errorf("square/go-jose: invalid SHA-1 thumbprint (must be %d bytes, not %d)", sha1.Size, x5tSHA1Len) + } + raw.X5tSHA1 = base64.RawURLEncoding.EncodeToString(k.CertificateThumbprintSHA1) + } + if x5tSHA256Len > 0 { + if x5tSHA256Len != sha256.Size { + return nil, fmt.Errorf("square/go-jose: invalid SHA-256 thumbprint (must be %d bytes, not %d)", sha256.Size, x5tSHA256Len) + } + raw.X5tSHA256 = base64.RawURLEncoding.EncodeToString(k.CertificateThumbprintSHA256) + } + + // If cert chain is attached (as opposed to being behind a URL), check the + // keys thumbprints to make sure they match what is expected. This is to + // ensure we don't accidentally produce a JWK with semantically inconsistent + // data in the headers. + if len(k.Certificates) > 0 { + expectedSHA1 := sha1.Sum(k.Certificates[0].Raw) + expectedSHA256 := sha256.Sum256(k.Certificates[0].Raw) + + if len(k.CertificateThumbprintSHA1) > 0 && !bytes.Equal(k.CertificateThumbprintSHA1, expectedSHA1[:]) { + return nil, errors.New("square/go-jose: invalid SHA-1 thumbprint, does not match cert chain") + } + if len(k.CertificateThumbprintSHA256) > 0 && !bytes.Equal(k.CertificateThumbprintSHA256, expectedSHA256[:]) { + return nil, errors.New("square/go-jose: invalid or SHA-256 thumbprint, does not match cert chain") + } + } + + raw.X5u = k.CertificatesURL + return json.Marshal(raw) } @@ -116,28 +169,61 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) { return err } + certs, err := parseCertificateChain(raw.X5c) + if err != nil { + return fmt.Errorf("square/go-jose: failed to unmarshal x5c field: %s", err) + } + var key interface{} + var certPub interface{} + var keyPub interface{} + + if len(certs) > 0 { + // We need to check that leaf public key matches the key embedded in this + // JWK, as required by the standard (see RFC 7517, Section 4.7). Otherwise + // the JWK parsed could be semantically invalid. Technically, should also + // check key usage fields and other extensions on the cert here, but the + // standard doesn't exactly explain how they're supposed to map from the + // JWK representation to the X.509 extensions. + certPub = certs[0].PublicKey + } + switch raw.Kty { case "EC": if raw.D != nil { key, err = raw.ecPrivateKey() + if err == nil { + keyPub = key.(*ecdsa.PrivateKey).Public() + } } else { key, err = raw.ecPublicKey() + keyPub = key } case "RSA": if raw.D != nil { key, err = raw.rsaPrivateKey() + if err == nil { + keyPub = key.(*rsa.PrivateKey).Public() + } } else { key, err = raw.rsaPublicKey() + keyPub = key } case "oct": + if certPub != nil { + return errors.New("square/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain") + } key, err = raw.symmetricKey() case "OKP": if raw.Crv == "Ed25519" && raw.X != nil { if raw.D != nil { key, err = raw.edPrivateKey() + if err == nil { + keyPub = key.(ed25519.PrivateKey).Public() + } } else { key, err = raw.edPublicKey() + keyPub = key } } else { err = fmt.Errorf("square/go-jose: unknown curve %s'", raw.Crv) @@ -146,12 +232,78 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) { err = fmt.Errorf("square/go-jose: unknown json web key type '%s'", raw.Kty) } - if err == nil { - *k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use} + if err != nil { + return + } - k.Certificates, err = parseCertificateChain(raw.X5c) + if certPub != nil && keyPub != nil { + if !reflect.DeepEqual(certPub, keyPub) { + return errors.New("square/go-jose: invalid JWK, public keys in key and x5c fields do not match") + } + } + + *k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs} + + k.CertificatesURL = raw.X5u + + // x5t parameters are base64url-encoded SHA thumbprints + // See RFC 7517, Section 4.8, https://tools.ietf.org/html/rfc7517#section-4.8 + x5tSHA1bytes, err := base64.RawURLEncoding.DecodeString(raw.X5tSHA1) + if err != nil { + return errors.New("square/go-jose: invalid JWK, x5t header has invalid encoding") + } + + // RFC 7517, Section 4.8 is ambiguous as to whether the digest output should be byte or hex, + // for this reason, after base64 decoding, if the size is sha1.Size it's likely that the value is a byte encoded + // checksum so we skip this. Otherwise if the checksum was hex encoded we expect a 40 byte sized array so we'll + // try to hex decode it. When Marshalling this value we'll always use a base64 encoded version of byte format checksum. + if len(x5tSHA1bytes) == 2*sha1.Size { + hx, err := hex.DecodeString(string(x5tSHA1bytes)) if err != nil { - return fmt.Errorf("failed to unmarshal x5c field: %s", err) + return fmt.Errorf("square/go-jose: invalid JWK, unable to hex decode x5t: %v", err) + + } + x5tSHA1bytes = hx + } + + k.CertificateThumbprintSHA1 = x5tSHA1bytes + + x5tSHA256bytes, err := base64.RawURLEncoding.DecodeString(raw.X5tSHA256) + if err != nil { + return errors.New("square/go-jose: invalid JWK, x5t#S256 header has invalid encoding") + } + + if len(x5tSHA256bytes) == 2*sha256.Size { + hx256, err := hex.DecodeString(string(x5tSHA256bytes)) + if err != nil { + return fmt.Errorf("square/go-jose: invalid JWK, unable to hex decode x5t#S256: %v", err) + } + x5tSHA256bytes = hx256 + } + + k.CertificateThumbprintSHA256 = x5tSHA256bytes + + x5tSHA1Len := len(k.CertificateThumbprintSHA1) + x5tSHA256Len := len(k.CertificateThumbprintSHA256) + if x5tSHA1Len > 0 && x5tSHA1Len != sha1.Size { + return errors.New("square/go-jose: invalid JWK, x5t header is of incorrect size") + } + if x5tSHA256Len > 0 && x5tSHA256Len != sha256.Size { + return errors.New("square/go-jose: invalid JWK, x5t#S256 header is of incorrect size") + } + + // If certificate chain *and* thumbprints are set, verify correctness. + if len(k.Certificates) > 0 { + leaf := k.Certificates[0] + sha1sum := sha1.Sum(leaf.Raw) + sha256sum := sha256.Sum256(leaf.Raw) + + if len(k.CertificateThumbprintSHA1) > 0 && !bytes.Equal(sha1sum[:], k.CertificateThumbprintSHA1) { + return errors.New("square/go-jose: invalid JWK, x5c thumbprint does not match x5t value") + } + + if len(k.CertificateThumbprintSHA256) > 0 && !bytes.Equal(sha256sum[:], k.CertificateThumbprintSHA256) { + return errors.New("square/go-jose: invalid JWK, x5c thumbprint does not match x5t#S256 value") } } @@ -180,7 +332,7 @@ func (s *JSONWebKeySet) Key(kid string) []JSONWebKey { const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}` const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}` -const edThumbprintTemplate = `{"crv":"%s","kty":"OKP",x":"%s"}` +const edThumbprintTemplate = `{"crv":"%s","kty":"OKP","x":"%s"}` func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) { coordLength := curveSize(curve) @@ -254,7 +406,7 @@ func (k *JSONWebKey) IsPublic() bool { } } -// Public creates JSONWebKey with corresponding publik key if JWK represents asymmetric private key. +// Public creates JSONWebKey with corresponding public key if JWK represents asymmetric private key. func (k *JSONWebKey) Public() JSONWebKey { if k.IsPublic() { return *k diff --git a/vendor/gopkg.in/square/go-jose.v2/jws.go b/vendor/gopkg.in/square/go-jose.v2/jws.go index e52a4766..7e261f93 100644 --- a/vendor/gopkg.in/square/go-jose.v2/jws.go +++ b/vendor/gopkg.in/square/go-jose.v2/jws.go @@ -102,14 +102,14 @@ func (sig Signature) mergedHeaders() rawHeader { } // Compute data to be signed -func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature) []byte { +func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature) ([]byte, error) { var authData bytes.Buffer protectedHeader := new(rawHeader) if signature.original != nil && signature.original.Protected != nil { if err := json.Unmarshal(signature.original.Protected.bytes(), protectedHeader); err != nil { - panic(err) + return nil, err } authData.WriteString(signature.original.Protected.base64()) } else if signature.protected != nil { @@ -134,7 +134,7 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature authData.Write(payload) } - return authData.Bytes() + return authData.Bytes(), nil } // parseSignedFull parses a message in full format. diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go b/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go new file mode 100644 index 00000000..3afa9030 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go @@ -0,0 +1,334 @@ +/*- + * Copyright 2016 Zbigniew Mandziejewicz + * Copyright 2016 Square, Inc. + * + * 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 jwt + +import ( + "bytes" + "reflect" + + "gopkg.in/square/go-jose.v2/json" + + "gopkg.in/square/go-jose.v2" +) + +// Builder is a utility for making JSON Web Tokens. Calls can be chained, and +// errors are accumulated until the final call to CompactSerialize/FullSerialize. +type Builder interface { + // Claims encodes claims into JWE/JWS form. Multiple calls will merge claims + // into single JSON object. If you are passing private claims, make sure to set + // struct field tags to specify the name for the JSON key to be used when + // serializing. + Claims(i interface{}) Builder + // Token builds a JSONWebToken from provided data. + Token() (*JSONWebToken, error) + // FullSerialize serializes a token using the full serialization format. + FullSerialize() (string, error) + // CompactSerialize serializes a token using the compact serialization format. + CompactSerialize() (string, error) +} + +// NestedBuilder is a utility for making Signed-Then-Encrypted JSON Web Tokens. +// Calls can be chained, and errors are accumulated until final call to +// CompactSerialize/FullSerialize. +type NestedBuilder interface { + // Claims encodes claims into JWE/JWS form. Multiple calls will merge claims + // into single JSON object. If you are passing private claims, make sure to set + // struct field tags to specify the name for the JSON key to be used when + // serializing. + Claims(i interface{}) NestedBuilder + // Token builds a NestedJSONWebToken from provided data. + Token() (*NestedJSONWebToken, error) + // FullSerialize serializes a token using the full serialization format. + FullSerialize() (string, error) + // CompactSerialize serializes a token using the compact serialization format. + CompactSerialize() (string, error) +} + +type builder struct { + payload map[string]interface{} + err error +} + +type signedBuilder struct { + builder + sig jose.Signer +} + +type encryptedBuilder struct { + builder + enc jose.Encrypter +} + +type nestedBuilder struct { + builder + sig jose.Signer + enc jose.Encrypter +} + +// Signed creates builder for signed tokens. +func Signed(sig jose.Signer) Builder { + return &signedBuilder{ + sig: sig, + } +} + +// Encrypted creates builder for encrypted tokens. +func Encrypted(enc jose.Encrypter) Builder { + return &encryptedBuilder{ + enc: enc, + } +} + +// SignedAndEncrypted creates builder for signed-then-encrypted tokens. +// ErrInvalidContentType will be returned if encrypter doesn't have JWT content type. +func SignedAndEncrypted(sig jose.Signer, enc jose.Encrypter) NestedBuilder { + if contentType, _ := enc.Options().ExtraHeaders[jose.HeaderContentType].(jose.ContentType); contentType != "JWT" { + return &nestedBuilder{ + builder: builder{ + err: ErrInvalidContentType, + }, + } + } + return &nestedBuilder{ + sig: sig, + enc: enc, + } +} + +func (b builder) claims(i interface{}) builder { + if b.err != nil { + return b + } + + m, ok := i.(map[string]interface{}) + switch { + case ok: + return b.merge(m) + case reflect.Indirect(reflect.ValueOf(i)).Kind() == reflect.Struct: + m, err := normalize(i) + if err != nil { + return builder{ + err: err, + } + } + return b.merge(m) + default: + return builder{ + err: ErrInvalidClaims, + } + } +} + +func normalize(i interface{}) (map[string]interface{}, error) { + m := make(map[string]interface{}) + + raw, err := json.Marshal(i) + if err != nil { + return nil, err + } + + d := json.NewDecoder(bytes.NewReader(raw)) + d.SetNumberType(json.UnmarshalJSONNumber) + + if err := d.Decode(&m); err != nil { + return nil, err + } + + return m, nil +} + +func (b *builder) merge(m map[string]interface{}) builder { + p := make(map[string]interface{}) + for k, v := range b.payload { + p[k] = v + } + for k, v := range m { + p[k] = v + } + + return builder{ + payload: p, + } +} + +func (b *builder) token(p func(interface{}) ([]byte, error), h []jose.Header) (*JSONWebToken, error) { + return &JSONWebToken{ + payload: p, + Headers: h, + }, nil +} + +func (b *signedBuilder) Claims(i interface{}) Builder { + return &signedBuilder{ + builder: b.builder.claims(i), + sig: b.sig, + } +} + +func (b *signedBuilder) Token() (*JSONWebToken, error) { + sig, err := b.sign() + if err != nil { + return nil, err + } + + h := make([]jose.Header, len(sig.Signatures)) + for i, v := range sig.Signatures { + h[i] = v.Header + } + + return b.builder.token(sig.Verify, h) +} + +func (b *signedBuilder) CompactSerialize() (string, error) { + sig, err := b.sign() + if err != nil { + return "", err + } + + return sig.CompactSerialize() +} + +func (b *signedBuilder) FullSerialize() (string, error) { + sig, err := b.sign() + if err != nil { + return "", err + } + + return sig.FullSerialize(), nil +} + +func (b *signedBuilder) sign() (*jose.JSONWebSignature, error) { + if b.err != nil { + return nil, b.err + } + + p, err := json.Marshal(b.payload) + if err != nil { + return nil, err + } + + return b.sig.Sign(p) +} + +func (b *encryptedBuilder) Claims(i interface{}) Builder { + return &encryptedBuilder{ + builder: b.builder.claims(i), + enc: b.enc, + } +} + +func (b *encryptedBuilder) CompactSerialize() (string, error) { + enc, err := b.encrypt() + if err != nil { + return "", err + } + + return enc.CompactSerialize() +} + +func (b *encryptedBuilder) FullSerialize() (string, error) { + enc, err := b.encrypt() + if err != nil { + return "", err + } + + return enc.FullSerialize(), nil +} + +func (b *encryptedBuilder) Token() (*JSONWebToken, error) { + enc, err := b.encrypt() + if err != nil { + return nil, err + } + + return b.builder.token(enc.Decrypt, []jose.Header{enc.Header}) +} + +func (b *encryptedBuilder) encrypt() (*jose.JSONWebEncryption, error) { + if b.err != nil { + return nil, b.err + } + + p, err := json.Marshal(b.payload) + if err != nil { + return nil, err + } + + return b.enc.Encrypt(p) +} + +func (b *nestedBuilder) Claims(i interface{}) NestedBuilder { + return &nestedBuilder{ + builder: b.builder.claims(i), + sig: b.sig, + enc: b.enc, + } +} + +func (b *nestedBuilder) Token() (*NestedJSONWebToken, error) { + enc, err := b.signAndEncrypt() + if err != nil { + return nil, err + } + + return &NestedJSONWebToken{ + enc: enc, + Headers: []jose.Header{enc.Header}, + }, nil +} + +func (b *nestedBuilder) CompactSerialize() (string, error) { + enc, err := b.signAndEncrypt() + if err != nil { + return "", err + } + + return enc.CompactSerialize() +} + +func (b *nestedBuilder) FullSerialize() (string, error) { + enc, err := b.signAndEncrypt() + if err != nil { + return "", err + } + + return enc.FullSerialize(), nil +} + +func (b *nestedBuilder) signAndEncrypt() (*jose.JSONWebEncryption, error) { + if b.err != nil { + return nil, b.err + } + + p, err := json.Marshal(b.payload) + if err != nil { + return nil, err + } + + sig, err := b.sig.Sign(p) + if err != nil { + return nil, err + } + + p2, err := sig.CompactSerialize() + if err != nil { + return nil, err + } + + return b.enc.Encrypt([]byte(p2)) +} diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/claims.go b/vendor/gopkg.in/square/go-jose.v2/jwt/claims.go new file mode 100644 index 00000000..5f40ef3b --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/jwt/claims.go @@ -0,0 +1,121 @@ +/*- + * Copyright 2016 Zbigniew Mandziejewicz + * Copyright 2016 Square, Inc. + * + * 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 jwt + +import ( + "strconv" + "time" + + "gopkg.in/square/go-jose.v2/json" +) + +// Claims represents public claim values (as specified in RFC 7519). +type Claims struct { + Issuer string `json:"iss,omitempty"` + Subject string `json:"sub,omitempty"` + Audience Audience `json:"aud,omitempty"` + Expiry *NumericDate `json:"exp,omitempty"` + NotBefore *NumericDate `json:"nbf,omitempty"` + IssuedAt *NumericDate `json:"iat,omitempty"` + ID string `json:"jti,omitempty"` +} + +// NumericDate represents date and time as the number of seconds since the +// epoch, ignoring leap seconds. Non-integer values can be represented +// in the serialized format, but we round to the nearest second. +// See RFC7519 Section 2: https://tools.ietf.org/html/rfc7519#section-2 +type NumericDate int64 + +// NewNumericDate constructs NumericDate from time.Time value. +func NewNumericDate(t time.Time) *NumericDate { + if t.IsZero() { + return nil + } + + // While RFC 7519 technically states that NumericDate values may be + // non-integer values, we don't bother serializing timestamps in + // claims with sub-second accurancy and just round to the nearest + // second instead. Not convined sub-second accuracy is useful here. + out := NumericDate(t.Unix()) + return &out +} + +// MarshalJSON serializes the given NumericDate into its JSON representation. +func (n NumericDate) MarshalJSON() ([]byte, error) { + return []byte(strconv.FormatInt(int64(n), 10)), nil +} + +// UnmarshalJSON reads a date from its JSON representation. +func (n *NumericDate) UnmarshalJSON(b []byte) error { + s := string(b) + + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return ErrUnmarshalNumericDate + } + + *n = NumericDate(f) + return nil +} + +// Time returns time.Time representation of NumericDate. +func (n *NumericDate) Time() time.Time { + if n == nil { + return time.Time{} + } + return time.Unix(int64(*n), 0) +} + +// Audience represents the recipients that the token is intended for. +type Audience []string + +// UnmarshalJSON reads an audience from its JSON representation. +func (s *Audience) UnmarshalJSON(b []byte) error { + var v interface{} + if err := json.Unmarshal(b, &v); err != nil { + return err + } + + switch v := v.(type) { + case string: + *s = []string{v} + case []interface{}: + a := make([]string, len(v)) + for i, e := range v { + s, ok := e.(string) + if !ok { + return ErrUnmarshalAudience + } + a[i] = s + } + *s = a + default: + return ErrUnmarshalAudience + } + + return nil +} + +func (s Audience) Contains(v string) bool { + for _, a := range s { + if a == v { + return true + } + } + return false +} diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/doc.go b/vendor/gopkg.in/square/go-jose.v2/jwt/doc.go new file mode 100644 index 00000000..4cf97b54 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/jwt/doc.go @@ -0,0 +1,22 @@ +/*- + * Copyright 2017 Square Inc. + * + * 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 jwt provides an implementation of the JSON Web Token standard. + +*/ +package jwt diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/errors.go b/vendor/gopkg.in/square/go-jose.v2/jwt/errors.go new file mode 100644 index 00000000..09f76ae4 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/jwt/errors.go @@ -0,0 +1,53 @@ +/*- + * Copyright 2016 Zbigniew Mandziejewicz + * Copyright 2016 Square, Inc. + * + * 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 jwt + +import "errors" + +// ErrUnmarshalAudience indicates that aud claim could not be unmarshalled. +var ErrUnmarshalAudience = errors.New("square/go-jose/jwt: expected string or array value to unmarshal to Audience") + +// ErrUnmarshalNumericDate indicates that JWT NumericDate could not be unmarshalled. +var ErrUnmarshalNumericDate = errors.New("square/go-jose/jwt: expected number value to unmarshal NumericDate") + +// ErrInvalidClaims indicates that given claims have invalid type. +var ErrInvalidClaims = errors.New("square/go-jose/jwt: expected claims to be value convertible into JSON object") + +// ErrInvalidIssuer indicates invalid iss claim. +var ErrInvalidIssuer = errors.New("square/go-jose/jwt: validation failed, invalid issuer claim (iss)") + +// ErrInvalidSubject indicates invalid sub claim. +var ErrInvalidSubject = errors.New("square/go-jose/jwt: validation failed, invalid subject claim (sub)") + +// ErrInvalidAudience indicated invalid aud claim. +var ErrInvalidAudience = errors.New("square/go-jose/jwt: validation failed, invalid audience claim (aud)") + +// ErrInvalidID indicates invalid jti claim. +var ErrInvalidID = errors.New("square/go-jose/jwt: validation failed, invalid ID claim (jti)") + +// ErrNotValidYet indicates that token is used before time indicated in nbf claim. +var ErrNotValidYet = errors.New("square/go-jose/jwt: validation failed, token not valid yet (nbf)") + +// ErrExpired indicates that token is used after expiry time indicated in exp claim. +var ErrExpired = errors.New("square/go-jose/jwt: validation failed, token is expired (exp)") + +// ErrIssuedInTheFuture indicates that the iat field is in the future. +var ErrIssuedInTheFuture = errors.New("square/go-jose/jwt: validation field, token issued in the future (iat)") + +// ErrInvalidContentType indicates that token requires JWT cty header. +var ErrInvalidContentType = errors.New("square/go-jose/jwt: expected content type to be JWT (cty header)") diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go b/vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go new file mode 100644 index 00000000..47498840 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go @@ -0,0 +1,169 @@ +/*- + * Copyright 2016 Zbigniew Mandziejewicz + * Copyright 2016 Square, Inc. + * + * 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 jwt + +import ( + "fmt" + "strings" + + jose "gopkg.in/square/go-jose.v2" + "gopkg.in/square/go-jose.v2/json" +) + +// JSONWebToken represents a JSON Web Token (as specified in RFC7519). +type JSONWebToken struct { + payload func(k interface{}) ([]byte, error) + unverifiedPayload func() []byte + Headers []jose.Header +} + +type NestedJSONWebToken struct { + enc *jose.JSONWebEncryption + Headers []jose.Header +} + +// Claims deserializes a JSONWebToken into dest using the provided key. +func (t *JSONWebToken) Claims(key interface{}, dest ...interface{}) error { + payloadKey := tryJWKS(t.Headers, key) + + b, err := t.payload(payloadKey) + if err != nil { + return err + } + + for _, d := range dest { + if err := json.Unmarshal(b, d); err != nil { + return err + } + } + + return nil +} + +// UnsafeClaimsWithoutVerification deserializes the claims of a +// JSONWebToken into the dests. For signed JWTs, the claims are not +// verified. This function won't work for encrypted JWTs. +func (t *JSONWebToken) UnsafeClaimsWithoutVerification(dest ...interface{}) error { + if t.unverifiedPayload == nil { + return fmt.Errorf("square/go-jose: Cannot get unverified claims") + } + claims := t.unverifiedPayload() + for _, d := range dest { + if err := json.Unmarshal(claims, d); err != nil { + return err + } + } + return nil +} + +func (t *NestedJSONWebToken) Decrypt(decryptionKey interface{}) (*JSONWebToken, error) { + key := tryJWKS(t.Headers, decryptionKey) + + b, err := t.enc.Decrypt(key) + if err != nil { + return nil, err + } + + sig, err := ParseSigned(string(b)) + if err != nil { + return nil, err + } + + return sig, nil +} + +// ParseSigned parses token from JWS form. +func ParseSigned(s string) (*JSONWebToken, error) { + sig, err := jose.ParseSigned(s) + if err != nil { + return nil, err + } + headers := make([]jose.Header, len(sig.Signatures)) + for i, signature := range sig.Signatures { + headers[i] = signature.Header + } + + return &JSONWebToken{ + payload: sig.Verify, + unverifiedPayload: sig.UnsafePayloadWithoutVerification, + Headers: headers, + }, nil +} + +// ParseEncrypted parses token from JWE form. +func ParseEncrypted(s string) (*JSONWebToken, error) { + enc, err := jose.ParseEncrypted(s) + if err != nil { + return nil, err + } + + return &JSONWebToken{ + payload: enc.Decrypt, + Headers: []jose.Header{enc.Header}, + }, nil +} + +// ParseSignedAndEncrypted parses signed-then-encrypted token from JWE form. +func ParseSignedAndEncrypted(s string) (*NestedJSONWebToken, error) { + enc, err := jose.ParseEncrypted(s) + if err != nil { + return nil, err + } + + contentType, _ := enc.Header.ExtraHeaders[jose.HeaderContentType].(string) + if strings.ToUpper(contentType) != "JWT" { + return nil, ErrInvalidContentType + } + + return &NestedJSONWebToken{ + enc: enc, + Headers: []jose.Header{enc.Header}, + }, nil +} + +func tryJWKS(headers []jose.Header, key interface{}) interface{} { + var jwks jose.JSONWebKeySet + + switch jwksType := key.(type) { + case *jose.JSONWebKeySet: + jwks = *jwksType + case jose.JSONWebKeySet: + jwks = jwksType + default: + return key + } + + var kid string + for _, header := range headers { + if header.KeyID != "" { + kid = header.KeyID + break + } + } + + if kid == "" { + return key + } + + keys := jwks.Key(kid) + if len(keys) == 0 { + return key + } + + return keys[0].Key +} diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/validation.go b/vendor/gopkg.in/square/go-jose.v2/jwt/validation.go new file mode 100644 index 00000000..6f3ff4e8 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/jwt/validation.go @@ -0,0 +1,114 @@ +/*- + * Copyright 2016 Zbigniew Mandziejewicz + * Copyright 2016 Square, Inc. + * + * 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 jwt + +import "time" + +const ( + // DefaultLeeway defines the default leeway for matching NotBefore/Expiry claims. + DefaultLeeway = 1.0 * time.Minute +) + +// Expected defines values used for protected claims validation. +// If field has zero value then validation is skipped. +type Expected struct { + // Issuer matches the "iss" claim exactly. + Issuer string + // Subject matches the "sub" claim exactly. + Subject string + // Audience matches the values in "aud" claim, regardless of their order. + Audience Audience + // ID matches the "jti" claim exactly. + ID string + // Time matches the "exp", "nbf" and "iat" claims with leeway. + Time time.Time +} + +// WithTime copies expectations with new time. +func (e Expected) WithTime(t time.Time) Expected { + e.Time = t + return e +} + +// Validate checks claims in a token against expected values. +// A default leeway value of one minute is used to compare time values. +// +// The default leeway will cause the token to be deemed valid until one +// minute after the expiration time. If you're a server application that +// wants to give an extra minute to client tokens, use this +// function. If you're a client application wondering if the server +// will accept your token, use ValidateWithLeeway with a leeway <=0, +// otherwise this function might make you think a token is valid when +// it is not. +func (c Claims) Validate(e Expected) error { + return c.ValidateWithLeeway(e, DefaultLeeway) +} + +// ValidateWithLeeway checks claims in a token against expected values. A +// custom leeway may be specified for comparing time values. You may pass a +// zero value to check time values with no leeway, but you should not that +// numeric date values are rounded to the nearest second and sub-second +// precision is not supported. +// +// The leeway gives some extra time to the token from the server's +// point of view. That is, if the token is expired, ValidateWithLeeway +// will still accept the token for 'leeway' amount of time. This fails +// if you're using this function to check if a server will accept your +// token, because it will think the token is valid even after it +// expires. So if you're a client validating if the token is valid to +// be submitted to a server, use leeway <=0, if you're a server +// validation a token, use leeway >=0. +func (c Claims) ValidateWithLeeway(e Expected, leeway time.Duration) error { + if e.Issuer != "" && e.Issuer != c.Issuer { + return ErrInvalidIssuer + } + + if e.Subject != "" && e.Subject != c.Subject { + return ErrInvalidSubject + } + + if e.ID != "" && e.ID != c.ID { + return ErrInvalidID + } + + if len(e.Audience) != 0 { + for _, v := range e.Audience { + if !c.Audience.Contains(v) { + return ErrInvalidAudience + } + } + } + + if !e.Time.IsZero() { + if c.NotBefore != nil && e.Time.Add(leeway).Before(c.NotBefore.Time()) { + return ErrNotValidYet + } + + if c.Expiry != nil && e.Time.Add(-leeway).After(c.Expiry.Time()) { + return ErrExpired + } + + // IssuedAt is optional but cannot be in the future. This is not required by the RFC, but + // something is misconfigured if this happens and we should not trust it. + if c.IssuedAt != nil && e.Time.Add(leeway).Before(c.IssuedAt.Time()) { + return ErrIssuedInTheFuture + } + } + + return nil +} diff --git a/vendor/gopkg.in/square/go-jose.v2/opaque.go b/vendor/gopkg.in/square/go-jose.v2/opaque.go index df747f99..fc3e8d2e 100644 --- a/vendor/gopkg.in/square/go-jose.v2/opaque.go +++ b/vendor/gopkg.in/square/go-jose.v2/opaque.go @@ -17,7 +17,7 @@ package jose // OpaqueSigner is an interface that supports signing payloads with opaque -// private key(s). Private key operations preformed by implementors may, for +// private key(s). Private key operations performed by implementers may, for // example, occur in a hardware module. An OpaqueSigner may rotate signing keys // transparently to the user of this interface. type OpaqueSigner interface { diff --git a/vendor/gopkg.in/square/go-jose.v2/shared.go b/vendor/gopkg.in/square/go-jose.v2/shared.go index f8438641..f72e5a53 100644 --- a/vendor/gopkg.in/square/go-jose.v2/shared.go +++ b/vendor/gopkg.in/square/go-jose.v2/shared.go @@ -183,7 +183,7 @@ type Header struct { // Unverified certificate chain parsed from x5c header. certificates []*x509.Certificate - // Any headers not recognised above get unmarshaled + // Any headers not recognised above get unmarshalled // from JSON in a generic manner and placed in this map. ExtraHeaders map[HeaderKey]interface{} } @@ -295,12 +295,12 @@ func (parsed rawHeader) getAPV() (*byteBuffer, error) { return parsed.getByteBuffer(headerAPV) } -// getIV extracts parsed "iv" frpom the raw JSON. +// getIV extracts parsed "iv" from the raw JSON. func (parsed rawHeader) getIV() (*byteBuffer, error) { return parsed.getByteBuffer(headerIV) } -// getTag extracts parsed "tag" frpom the raw JSON. +// getTag extracts parsed "tag" from the raw JSON. func (parsed rawHeader) getTag() (*byteBuffer, error) { return parsed.getByteBuffer(headerTag) } diff --git a/vendor/gopkg.in/square/go-jose.v2/signing.go b/vendor/gopkg.in/square/go-jose.v2/signing.go index 664a51cc..bad820ce 100644 --- a/vendor/gopkg.in/square/go-jose.v2/signing.go +++ b/vendor/gopkg.in/square/go-jose.v2/signing.go @@ -370,7 +370,11 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter } } - input := obj.computeAuthData(payload, &signature) + input, err := obj.computeAuthData(payload, &signature) + if err != nil { + return ErrCryptoFailure + } + alg := headers.getSignatureAlgorithm() err = verifier.verifyPayload(input, signature.Signature, alg) if err == nil { @@ -421,7 +425,11 @@ outer: } } - input := obj.computeAuthData(payload, &signature) + input, err := obj.computeAuthData(payload, &signature) + if err != nil { + continue + } + alg := headers.getSignatureAlgorithm() err = verifier.verifyPayload(input, signature.Signature, alg) if err == nil { diff --git a/vendor/modules.txt b/vendor/modules.txt index 648e7327..3b296241 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -62,9 +62,6 @@ github.com/coredns/coredns/plugin/pkg/transport github.com/coredns/coredns/plugin/pkg/uniq github.com/coredns/coredns/plugin/test github.com/coredns/coredns/request -# github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73 -## explicit -github.com/coreos/go-oidc/jose # github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf ## explicit github.com/coreos/go-systemd/daemon @@ -530,17 +527,18 @@ google.golang.org/protobuf/types/descriptorpb google.golang.org/protobuf/types/known/anypb google.golang.org/protobuf/types/known/durationpb google.golang.org/protobuf/types/known/timestamppb -# gopkg.in/coreos/go-oidc.v2 v2.1.0 +# gopkg.in/coreos/go-oidc.v2 v2.2.1 ## explicit gopkg.in/coreos/go-oidc.v2 # gopkg.in/natefinch/lumberjack.v2 v2.0.0 ## explicit gopkg.in/natefinch/lumberjack.v2 -# gopkg.in/square/go-jose.v2 v2.4.0 +# gopkg.in/square/go-jose.v2 v2.6.0 ## explicit gopkg.in/square/go-jose.v2 gopkg.in/square/go-jose.v2/cipher gopkg.in/square/go-jose.v2/json +gopkg.in/square/go-jose.v2/jwt # gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 ## explicit gopkg.in/tomb.v1