mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +00:00
Merge pull request #56161 from ericchiang/go-jose-import
Automatic merge from submit-queue (batch tested with PRs 56161, 56324, 55685, 56409, 55296). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. bootstrap: use gopkg.in import for square/go-jose xref #55514 For 1.10. Ignore while 1.9 code freeze is in effect. ```release-note NONE ```
This commit is contained in:
commit
34e73a77ac
27
Godeps/Godeps.json
generated
27
Godeps/Godeps.json
generated
@ -2488,18 +2488,6 @@
|
|||||||
"ImportPath": "github.com/spf13/viper",
|
"ImportPath": "github.com/spf13/viper",
|
||||||
"Rev": "7fb2782df3d83e0036cc89f461ed0422628776f4"
|
"Rev": "7fb2782df3d83e0036cc89f461ed0422628776f4"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/square/go-jose",
|
|
||||||
"Rev": "789a4c4bd4c118f7564954f441b29c153ccd6a96"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/square/go-jose/cipher",
|
|
||||||
"Rev": "789a4c4bd4c118f7564954f441b29c153ccd6a96"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/square/go-jose/json",
|
|
||||||
"Rev": "789a4c4bd4c118f7564954f441b29c153ccd6a96"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/storageos/go-api",
|
"ImportPath": "github.com/storageos/go-api",
|
||||||
"Rev": "74f9beb613cacf0cc282facc2e1550a3231e126f"
|
"Rev": "74f9beb613cacf0cc282facc2e1550a3231e126f"
|
||||||
@ -3028,6 +3016,21 @@
|
|||||||
"Comment": "v1.0-16-g20b71e5",
|
"Comment": "v1.0-16-g20b71e5",
|
||||||
"Rev": "20b71e5b60d756d3d2f80def009790325acc2b23"
|
"Rev": "20b71e5b60d756d3d2f80def009790325acc2b23"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/square/go-jose.v2",
|
||||||
|
"Comment": "v2.1.3",
|
||||||
|
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
||||||
|
"Comment": "v2.1.3",
|
||||||
|
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
||||||
|
"Comment": "v2.1.3",
|
||||||
|
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/warnings.v0",
|
"ImportPath": "gopkg.in/warnings.v0",
|
||||||
"Comment": "v0.1.1",
|
"Comment": "v0.1.1",
|
||||||
|
1260
Godeps/LICENSES
generated
1260
Godeps/LICENSES
generated
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,7 @@ go_library(
|
|||||||
"//pkg/bootstrap/api:go_default_library",
|
"//pkg/bootstrap/api:go_default_library",
|
||||||
"//pkg/util/metrics:go_default_library",
|
"//pkg/util/metrics:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/github.com/square/go-jose:go_default_library",
|
"//vendor/gopkg.in/square/go-jose.v2:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -20,19 +20,28 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jose "github.com/square/go-jose"
|
jose "gopkg.in/square/go-jose.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// computeDetachedSig takes content and token details and computes a detached
|
// computeDetachedSig takes content and token details and computes a detached
|
||||||
// JWS signature. This is described in Appendix F of RFC 7515. Basically, this
|
// JWS signature. This is described in Appendix F of RFC 7515. Basically, this
|
||||||
// is a regular JWS with the content part of the signature elided.
|
// is a regular JWS with the content part of the signature elided.
|
||||||
func computeDetachedSig(content, tokenID, tokenSecret string) (string, error) {
|
func computeDetachedSig(content, tokenID, tokenSecret string) (string, error) {
|
||||||
jwk := &jose.JsonWebKey{
|
jwk := &jose.JSONWebKey{
|
||||||
Key: []byte(tokenSecret),
|
Key: []byte(tokenSecret),
|
||||||
KeyID: tokenID,
|
KeyID: tokenID,
|
||||||
}
|
}
|
||||||
|
|
||||||
signer, err := jose.NewSigner(jose.HS256, jwk)
|
opts := &jose.SignerOptions{
|
||||||
|
// Since this is a symetric key, go-jose doesn't automatically include
|
||||||
|
// the KeyID as part of the protected header. We have to pass it here
|
||||||
|
// explicitly.
|
||||||
|
ExtraHeaders: map[jose.HeaderKey]interface{}{
|
||||||
|
"kid": tokenID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: jwk}, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("can't make a HS256 signer from the given token: %v", err)
|
return "", fmt.Errorf("can't make a HS256 signer from the given token: %v", err)
|
||||||
}
|
}
|
||||||
|
2
vendor/BUILD
vendored
2
vendor/BUILD
vendored
@ -328,7 +328,6 @@ filegroup(
|
|||||||
"//vendor/github.com/spf13/jwalterweatherman:all-srcs",
|
"//vendor/github.com/spf13/jwalterweatherman:all-srcs",
|
||||||
"//vendor/github.com/spf13/pflag:all-srcs",
|
"//vendor/github.com/spf13/pflag:all-srcs",
|
||||||
"//vendor/github.com/spf13/viper:all-srcs",
|
"//vendor/github.com/spf13/viper:all-srcs",
|
||||||
"//vendor/github.com/square/go-jose:all-srcs",
|
|
||||||
"//vendor/github.com/storageos/go-api:all-srcs",
|
"//vendor/github.com/storageos/go-api:all-srcs",
|
||||||
"//vendor/github.com/stretchr/objx:all-srcs",
|
"//vendor/github.com/stretchr/objx:all-srcs",
|
||||||
"//vendor/github.com/stretchr/testify/assert:all-srcs",
|
"//vendor/github.com/stretchr/testify/assert:all-srcs",
|
||||||
@ -397,6 +396,7 @@ filegroup(
|
|||||||
"//vendor/gopkg.in/gcfg.v1:all-srcs",
|
"//vendor/gopkg.in/gcfg.v1:all-srcs",
|
||||||
"//vendor/gopkg.in/inf.v0:all-srcs",
|
"//vendor/gopkg.in/inf.v0:all-srcs",
|
||||||
"//vendor/gopkg.in/natefinch/lumberjack.v2:all-srcs",
|
"//vendor/gopkg.in/natefinch/lumberjack.v2:all-srcs",
|
||||||
|
"//vendor/gopkg.in/square/go-jose.v2:all-srcs",
|
||||||
"//vendor/gopkg.in/warnings.v0:all-srcs",
|
"//vendor/gopkg.in/warnings.v0:all-srcs",
|
||||||
"//vendor/gopkg.in/yaml.v2:all-srcs",
|
"//vendor/gopkg.in/yaml.v2:all-srcs",
|
||||||
"//vendor/k8s.io/gengo/args:all-srcs",
|
"//vendor/k8s.io/gengo/args:all-srcs",
|
||||||
|
212
vendor/github.com/square/go-jose/README.md
generated
vendored
212
vendor/github.com/square/go-jose/README.md
generated
vendored
@ -1,212 +0,0 @@
|
|||||||
# Go JOSE
|
|
||||||
|
|
||||||
[](https://godoc.org/gopkg.in/square/go-jose.v1) [](https://raw.githubusercontent.com/square/go-jose/master/LICENSE)
|
|
||||||
[](https://github.com/square/go-jose/releases)
|
|
||||||
[](https://travis-ci.org/square/go-jose)
|
|
||||||
[](https://coveralls.io/r/square/go-jose)
|
|
||||||
|
|
||||||
Package jose aims to provide an implementation of the Javascript Object Signing
|
|
||||||
and Encryption set of standards. For the moment, it mainly focuses on encryption
|
|
||||||
and signing based on the JSON Web Encryption and JSON Web Signature standards.
|
|
||||||
|
|
||||||
**Disclaimer**: This library contains encryption software that is subject to
|
|
||||||
the U.S. Export Administration Regulations. You may not export, re-export,
|
|
||||||
transfer or download this code or any part of it in violation of any United
|
|
||||||
States law, directive or regulation. In particular this software may not be
|
|
||||||
exported or re-exported in any form or on any media to Iran, North Sudan,
|
|
||||||
Syria, Cuba, or North Korea, or to denied persons or entities mentioned on any
|
|
||||||
US maintained blocked list.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The implementation follows the
|
|
||||||
[JSON Web Encryption](http://dx.doi.org/10.17487/RFC7516)
|
|
||||||
standard (RFC 7516) and
|
|
||||||
[JSON Web Signature](http://dx.doi.org/10.17487/RFC7515)
|
|
||||||
standard (RFC 7515). Tables of supported algorithms are shown below.
|
|
||||||
The library supports both the compact and full serialization formats, and has
|
|
||||||
optional support for multiple recipients. It also comes with a small
|
|
||||||
command-line utility
|
|
||||||
([`jose-util`](https://github.com/square/go-jose/tree/master/jose-util))
|
|
||||||
for dealing with JOSE messages in a shell.
|
|
||||||
|
|
||||||
**Note**: We use a forked version of the `encoding/json` package from the Go
|
|
||||||
standard library which uses case-sensitive matching for member names (instead
|
|
||||||
of [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html)).
|
|
||||||
This is to avoid differences in interpretation of messages between go-jose and
|
|
||||||
libraries in other languages. If you do not like this behavior, you can use the
|
|
||||||
`std_json` build tag to disable it (though we do not recommend doing so).
|
|
||||||
|
|
||||||
### Versions
|
|
||||||
|
|
||||||
We use [gopkg.in](https://gopkg.in) for versioning.
|
|
||||||
|
|
||||||
[Version 1](https://gopkg.in/square/go-jose.v1) is the current stable version:
|
|
||||||
|
|
||||||
import "gopkg.in/square/go-jose.v1"
|
|
||||||
|
|
||||||
The interface for [go-jose.v1](https://gopkg.in/square/go-jose.v1) will remain
|
|
||||||
backwards compatible. We're currently sketching out ideas for a new version, to
|
|
||||||
clean up the interface a bit. If you have ideas or feature requests [please let
|
|
||||||
us know](https://github.com/square/go-jose/issues/64)!
|
|
||||||
|
|
||||||
### Supported algorithms
|
|
||||||
|
|
||||||
See below for a table of supported algorithms. Algorithm identifiers match
|
|
||||||
the names in the
|
|
||||||
[JSON Web Algorithms](http://dx.doi.org/10.17487/RFC7518)
|
|
||||||
standard where possible. The
|
|
||||||
[Godoc reference](https://godoc.org/github.com/square/go-jose#pkg-constants)
|
|
||||||
has a list of constants.
|
|
||||||
|
|
||||||
Key encryption | Algorithm identifier(s)
|
|
||||||
:------------------------- | :------------------------------
|
|
||||||
RSA-PKCS#1v1.5 | RSA1_5
|
|
||||||
RSA-OAEP | RSA-OAEP, RSA-OAEP-256
|
|
||||||
AES key wrap | A128KW, A192KW, A256KW
|
|
||||||
AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW
|
|
||||||
ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW
|
|
||||||
ECDH-ES (direct) | ECDH-ES<sup>1</sup>
|
|
||||||
Direct encryption | dir<sup>1</sup>
|
|
||||||
|
|
||||||
<sup>1. Not supported in multi-recipient mode</sup>
|
|
||||||
|
|
||||||
Signing / MAC | Algorithm identifier(s)
|
|
||||||
:------------------------- | :------------------------------
|
|
||||||
RSASSA-PKCS#1v1.5 | RS256, RS384, RS512
|
|
||||||
RSASSA-PSS | PS256, PS384, PS512
|
|
||||||
HMAC | HS256, HS384, HS512
|
|
||||||
ECDSA | ES256, ES384, ES512
|
|
||||||
|
|
||||||
Content encryption | Algorithm identifier(s)
|
|
||||||
:------------------------- | :------------------------------
|
|
||||||
AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512
|
|
||||||
AES-GCM | A128GCM, A192GCM, A256GCM
|
|
||||||
|
|
||||||
Compression | Algorithm identifiers(s)
|
|
||||||
:------------------------- | -------------------------------
|
|
||||||
DEFLATE (RFC 1951) | DEF
|
|
||||||
|
|
||||||
### Supported key types
|
|
||||||
|
|
||||||
See below for a table of supported key types. These are understood by the
|
|
||||||
library, and can be passed to corresponding functions such as `NewEncrypter` or
|
|
||||||
`NewSigner`. Note that if you are creating a new encrypter or signer with a
|
|
||||||
JsonWebKey, the key id of the JsonWebKey (if present) will be added to any
|
|
||||||
resulting messages.
|
|
||||||
|
|
||||||
Algorithm(s) | Corresponding types
|
|
||||||
:------------------------- | -------------------------------
|
|
||||||
RSA | *[rsa.PublicKey](http://golang.org/pkg/crypto/rsa/#PublicKey), *[rsa.PrivateKey](http://golang.org/pkg/crypto/rsa/#PrivateKey), *[jose.JsonWebKey](https://godoc.org/github.com/square/go-jose#JsonWebKey)
|
|
||||||
ECDH, ECDSA | *[ecdsa.PublicKey](http://golang.org/pkg/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](http://golang.org/pkg/crypto/ecdsa/#PrivateKey), *[jose.JsonWebKey](https://godoc.org/github.com/square/go-jose#JsonWebKey)
|
|
||||||
AES, HMAC | []byte, *[jose.JsonWebKey](https://godoc.org/github.com/square/go-jose#JsonWebKey)
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Encryption/decryption example using RSA:
|
|
||||||
|
|
||||||
```Go
|
|
||||||
// Generate a public/private key pair to use for this example. The library
|
|
||||||
// also provides two utility functions (LoadPublicKey and LoadPrivateKey)
|
|
||||||
// that can be used to load keys from PEM/DER-encoded data.
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instantiate an encrypter using RSA-OAEP with AES128-GCM. An error would
|
|
||||||
// indicate that the selected algorithm(s) are not currently supported.
|
|
||||||
publicKey := &privateKey.PublicKey
|
|
||||||
encrypter, err := NewEncrypter(RSA_OAEP, A128GCM, publicKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt a sample plaintext. Calling the encrypter returns an encrypted
|
|
||||||
// JWE object, which can then be serialized for output afterwards. An error
|
|
||||||
// would indicate a problem in an underlying cryptographic primitive.
|
|
||||||
var plaintext = []byte("Lorem ipsum dolor sit amet")
|
|
||||||
object, err := encrypter.Encrypt(plaintext)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize the encrypted object using the full serialization format.
|
|
||||||
// Alternatively you can also use the compact format here by calling
|
|
||||||
// object.CompactSerialize() instead.
|
|
||||||
serialized := object.FullSerialize()
|
|
||||||
|
|
||||||
// Parse the serialized, encrypted JWE object. An error would indicate that
|
|
||||||
// the given input did not represent a valid message.
|
|
||||||
object, err = ParseEncrypted(serialized)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we can decrypt and get back our original plaintext. An error here
|
|
||||||
// would indicate the the message failed to decrypt, e.g. because the auth
|
|
||||||
// tag was broken or the message was tampered with.
|
|
||||||
decrypted, err := object.Decrypt(privateKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf(string(decrypted))
|
|
||||||
// output: Lorem ipsum dolor sit amet
|
|
||||||
```
|
|
||||||
|
|
||||||
Signing/verification example using RSA:
|
|
||||||
|
|
||||||
```Go
|
|
||||||
// Generate a public/private key pair to use for this example. The library
|
|
||||||
// also provides two utility functions (LoadPublicKey and LoadPrivateKey)
|
|
||||||
// that can be used to load keys from PEM/DER-encoded data.
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instantiate a signer using RSASSA-PSS (SHA512) with the given private key.
|
|
||||||
signer, err := NewSigner(PS512, privateKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign a sample payload. Calling the signer returns a protected JWS object,
|
|
||||||
// which can then be serialized for output afterwards. An error would
|
|
||||||
// indicate a problem in an underlying cryptographic primitive.
|
|
||||||
var payload = []byte("Lorem ipsum dolor sit amet")
|
|
||||||
object, err := signer.Sign(payload)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize the encrypted object using the full serialization format.
|
|
||||||
// Alternatively you can also use the compact format here by calling
|
|
||||||
// object.CompactSerialize() instead.
|
|
||||||
serialized := object.FullSerialize()
|
|
||||||
|
|
||||||
// Parse the serialized, protected JWS object. An error would indicate that
|
|
||||||
// the given input did not represent a valid message.
|
|
||||||
object, err = ParseSigned(serialized)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we can verify the signature on the payload. An error here would
|
|
||||||
// indicate the the message failed to verify, e.g. because the signature was
|
|
||||||
// broken or the message was tampered with.
|
|
||||||
output, err := object.Verify(&privateKey.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf(string(output))
|
|
||||||
// output: Lorem ipsum dolor sit amet
|
|
||||||
```
|
|
||||||
|
|
||||||
More examples can be found in the [Godoc
|
|
||||||
reference](https://godoc.org/github.com/square/go-jose) for this package. The
|
|
||||||
[`jose-util`](https://github.com/square/go-jose/tree/master/jose-util)
|
|
||||||
subdirectory also contains a small command-line utility which might
|
|
||||||
be useful as an example.
|
|
349
vendor/github.com/square/go-jose/crypter.go
generated
vendored
349
vendor/github.com/square/go-jose/crypter.go
generated
vendored
@ -1,349 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright 2014 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 jose
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/rsa"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Encrypter represents an encrypter which produces an encrypted JWE object.
|
|
||||||
type Encrypter interface {
|
|
||||||
Encrypt(plaintext []byte) (*JsonWebEncryption, error)
|
|
||||||
EncryptWithAuthData(plaintext []byte, aad []byte) (*JsonWebEncryption, error)
|
|
||||||
SetCompression(alg CompressionAlgorithm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MultiEncrypter represents an encrypter which supports multiple recipients.
|
|
||||||
type MultiEncrypter interface {
|
|
||||||
Encrypt(plaintext []byte) (*JsonWebEncryption, error)
|
|
||||||
EncryptWithAuthData(plaintext []byte, aad []byte) (*JsonWebEncryption, error)
|
|
||||||
SetCompression(alg CompressionAlgorithm)
|
|
||||||
AddRecipient(alg KeyAlgorithm, encryptionKey interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// A generic content cipher
|
|
||||||
type contentCipher interface {
|
|
||||||
keySize() int
|
|
||||||
encrypt(cek []byte, aad, plaintext []byte) (*aeadParts, error)
|
|
||||||
decrypt(cek []byte, aad []byte, parts *aeadParts) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A key generator (for generating/getting a CEK)
|
|
||||||
type keyGenerator interface {
|
|
||||||
keySize() int
|
|
||||||
genKey() ([]byte, rawHeader, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A generic key encrypter
|
|
||||||
type keyEncrypter interface {
|
|
||||||
encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) // Encrypt a key
|
|
||||||
}
|
|
||||||
|
|
||||||
// A generic key decrypter
|
|
||||||
type keyDecrypter interface {
|
|
||||||
decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) // Decrypt a key
|
|
||||||
}
|
|
||||||
|
|
||||||
// A generic encrypter based on the given key encrypter and content cipher.
|
|
||||||
type genericEncrypter struct {
|
|
||||||
contentAlg ContentEncryption
|
|
||||||
compressionAlg CompressionAlgorithm
|
|
||||||
cipher contentCipher
|
|
||||||
recipients []recipientKeyInfo
|
|
||||||
keyGenerator keyGenerator
|
|
||||||
}
|
|
||||||
|
|
||||||
type recipientKeyInfo struct {
|
|
||||||
keyID string
|
|
||||||
keyAlg KeyAlgorithm
|
|
||||||
keyEncrypter keyEncrypter
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCompression sets a compression algorithm to be applied before encryption.
|
|
||||||
func (ctx *genericEncrypter) SetCompression(compressionAlg CompressionAlgorithm) {
|
|
||||||
ctx.compressionAlg = compressionAlg
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEncrypter creates an appropriate encrypter based on the key type
|
|
||||||
func NewEncrypter(alg KeyAlgorithm, enc ContentEncryption, encryptionKey interface{}) (Encrypter, error) {
|
|
||||||
encrypter := &genericEncrypter{
|
|
||||||
contentAlg: enc,
|
|
||||||
compressionAlg: NONE,
|
|
||||||
recipients: []recipientKeyInfo{},
|
|
||||||
cipher: getContentCipher(enc),
|
|
||||||
}
|
|
||||||
|
|
||||||
if encrypter.cipher == nil {
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
var keyID string
|
|
||||||
var rawKey interface{}
|
|
||||||
switch encryptionKey := encryptionKey.(type) {
|
|
||||||
case *JsonWebKey:
|
|
||||||
keyID = encryptionKey.KeyID
|
|
||||||
rawKey = encryptionKey.Key
|
|
||||||
default:
|
|
||||||
rawKey = encryptionKey
|
|
||||||
}
|
|
||||||
|
|
||||||
switch alg {
|
|
||||||
case DIRECT:
|
|
||||||
// Direct encryption mode must be treated differently
|
|
||||||
if reflect.TypeOf(rawKey) != reflect.TypeOf([]byte{}) {
|
|
||||||
return nil, ErrUnsupportedKeyType
|
|
||||||
}
|
|
||||||
encrypter.keyGenerator = staticKeyGenerator{
|
|
||||||
key: rawKey.([]byte),
|
|
||||||
}
|
|
||||||
recipient, _ := newSymmetricRecipient(alg, rawKey.([]byte))
|
|
||||||
if keyID != "" {
|
|
||||||
recipient.keyID = keyID
|
|
||||||
}
|
|
||||||
encrypter.recipients = []recipientKeyInfo{recipient}
|
|
||||||
return encrypter, nil
|
|
||||||
case ECDH_ES:
|
|
||||||
// ECDH-ES (w/o key wrapping) is similar to DIRECT mode
|
|
||||||
typeOf := reflect.TypeOf(rawKey)
|
|
||||||
if typeOf != reflect.TypeOf(&ecdsa.PublicKey{}) {
|
|
||||||
return nil, ErrUnsupportedKeyType
|
|
||||||
}
|
|
||||||
encrypter.keyGenerator = ecKeyGenerator{
|
|
||||||
size: encrypter.cipher.keySize(),
|
|
||||||
algID: string(enc),
|
|
||||||
publicKey: rawKey.(*ecdsa.PublicKey),
|
|
||||||
}
|
|
||||||
recipient, _ := newECDHRecipient(alg, rawKey.(*ecdsa.PublicKey))
|
|
||||||
if keyID != "" {
|
|
||||||
recipient.keyID = keyID
|
|
||||||
}
|
|
||||||
encrypter.recipients = []recipientKeyInfo{recipient}
|
|
||||||
return encrypter, nil
|
|
||||||
default:
|
|
||||||
// Can just add a standard recipient
|
|
||||||
encrypter.keyGenerator = randomKeyGenerator{
|
|
||||||
size: encrypter.cipher.keySize(),
|
|
||||||
}
|
|
||||||
err := encrypter.AddRecipient(alg, encryptionKey)
|
|
||||||
return encrypter, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMultiEncrypter creates a multi-encrypter based on the given parameters
|
|
||||||
func NewMultiEncrypter(enc ContentEncryption) (MultiEncrypter, error) {
|
|
||||||
cipher := getContentCipher(enc)
|
|
||||||
|
|
||||||
if cipher == nil {
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypter := &genericEncrypter{
|
|
||||||
contentAlg: enc,
|
|
||||||
compressionAlg: NONE,
|
|
||||||
recipients: []recipientKeyInfo{},
|
|
||||||
cipher: cipher,
|
|
||||||
keyGenerator: randomKeyGenerator{
|
|
||||||
size: cipher.keySize(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return encrypter, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *genericEncrypter) AddRecipient(alg KeyAlgorithm, encryptionKey interface{}) (err error) {
|
|
||||||
var recipient recipientKeyInfo
|
|
||||||
|
|
||||||
switch alg {
|
|
||||||
case DIRECT, ECDH_ES:
|
|
||||||
return fmt.Errorf("square/go-jose: key algorithm '%s' not supported in multi-recipient mode", alg)
|
|
||||||
}
|
|
||||||
|
|
||||||
recipient, err = makeJWERecipient(alg, encryptionKey)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
ctx.recipients = append(ctx.recipients, recipient)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKeyInfo, error) {
|
|
||||||
switch encryptionKey := encryptionKey.(type) {
|
|
||||||
case *rsa.PublicKey:
|
|
||||||
return newRSARecipient(alg, encryptionKey)
|
|
||||||
case *ecdsa.PublicKey:
|
|
||||||
return newECDHRecipient(alg, encryptionKey)
|
|
||||||
case []byte:
|
|
||||||
return newSymmetricRecipient(alg, encryptionKey)
|
|
||||||
case *JsonWebKey:
|
|
||||||
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
|
|
||||||
if err == nil && encryptionKey.KeyID != "" {
|
|
||||||
recipient.keyID = encryptionKey.KeyID
|
|
||||||
}
|
|
||||||
return recipient, err
|
|
||||||
default:
|
|
||||||
return recipientKeyInfo{}, ErrUnsupportedKeyType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDecrypter creates an appropriate decrypter based on the key type
|
|
||||||
func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) {
|
|
||||||
switch decryptionKey := decryptionKey.(type) {
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
return &rsaDecrypterSigner{
|
|
||||||
privateKey: decryptionKey,
|
|
||||||
}, nil
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
return &ecDecrypterSigner{
|
|
||||||
privateKey: decryptionKey,
|
|
||||||
}, nil
|
|
||||||
case []byte:
|
|
||||||
return &symmetricKeyCipher{
|
|
||||||
key: decryptionKey,
|
|
||||||
}, nil
|
|
||||||
case *JsonWebKey:
|
|
||||||
return newDecrypter(decryptionKey.Key)
|
|
||||||
default:
|
|
||||||
return nil, ErrUnsupportedKeyType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of encrypt method producing a JWE object.
|
|
||||||
func (ctx *genericEncrypter) Encrypt(plaintext []byte) (*JsonWebEncryption, error) {
|
|
||||||
return ctx.EncryptWithAuthData(plaintext, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of encrypt method producing a JWE object.
|
|
||||||
func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JsonWebEncryption, error) {
|
|
||||||
obj := &JsonWebEncryption{}
|
|
||||||
obj.aad = aad
|
|
||||||
|
|
||||||
obj.protected = &rawHeader{
|
|
||||||
Enc: ctx.contentAlg,
|
|
||||||
}
|
|
||||||
obj.recipients = make([]recipientInfo, len(ctx.recipients))
|
|
||||||
|
|
||||||
if len(ctx.recipients) == 0 {
|
|
||||||
return nil, fmt.Errorf("square/go-jose: no recipients to encrypt to")
|
|
||||||
}
|
|
||||||
|
|
||||||
cek, headers, err := ctx.keyGenerator.genKey()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.protected.merge(&headers)
|
|
||||||
|
|
||||||
for i, info := range ctx.recipients {
|
|
||||||
recipient, err := info.keyEncrypter.encryptKey(cek, info.keyAlg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
recipient.header.Alg = string(info.keyAlg)
|
|
||||||
if info.keyID != "" {
|
|
||||||
recipient.header.Kid = info.keyID
|
|
||||||
}
|
|
||||||
obj.recipients[i] = recipient
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ctx.recipients) == 1 {
|
|
||||||
// Move per-recipient headers into main protected header if there's
|
|
||||||
// only a single recipient.
|
|
||||||
obj.protected.merge(obj.recipients[0].header)
|
|
||||||
obj.recipients[0].header = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.compressionAlg != NONE {
|
|
||||||
plaintext, err = compress(ctx.compressionAlg, plaintext)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.protected.Zip = ctx.compressionAlg
|
|
||||||
}
|
|
||||||
|
|
||||||
authData := obj.computeAuthData()
|
|
||||||
parts, err := ctx.cipher.encrypt(cek, authData, plaintext)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.iv = parts.iv
|
|
||||||
obj.ciphertext = parts.ciphertext
|
|
||||||
obj.tag = parts.tag
|
|
||||||
|
|
||||||
return obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt and validate the object and return the plaintext.
|
|
||||||
func (obj JsonWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) {
|
|
||||||
headers := obj.mergedHeaders(nil)
|
|
||||||
|
|
||||||
if len(headers.Crit) > 0 {
|
|
||||||
return nil, fmt.Errorf("square/go-jose: unsupported crit header")
|
|
||||||
}
|
|
||||||
|
|
||||||
decrypter, err := newDecrypter(decryptionKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cipher := getContentCipher(headers.Enc)
|
|
||||||
if cipher == nil {
|
|
||||||
return nil, fmt.Errorf("square/go-jose: unsupported enc value '%s'", string(headers.Enc))
|
|
||||||
}
|
|
||||||
|
|
||||||
generator := randomKeyGenerator{
|
|
||||||
size: cipher.keySize(),
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := &aeadParts{
|
|
||||||
iv: obj.iv,
|
|
||||||
ciphertext: obj.ciphertext,
|
|
||||||
tag: obj.tag,
|
|
||||||
}
|
|
||||||
|
|
||||||
authData := obj.computeAuthData()
|
|
||||||
|
|
||||||
var plaintext []byte
|
|
||||||
for _, recipient := range obj.recipients {
|
|
||||||
recipientHeaders := obj.mergedHeaders(&recipient)
|
|
||||||
|
|
||||||
cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator)
|
|
||||||
if err == nil {
|
|
||||||
// Found a valid CEK -- let's try to decrypt.
|
|
||||||
plaintext, err = cipher.decrypt(cek, authData, parts)
|
|
||||||
if err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if plaintext == nil {
|
|
||||||
return nil, ErrCryptoFailure
|
|
||||||
}
|
|
||||||
|
|
||||||
// The "zip" header parameter may only be present in the protected header.
|
|
||||||
if obj.protected.Zip != "" {
|
|
||||||
plaintext, err = decompress(obj.protected.Zip, plaintext)
|
|
||||||
}
|
|
||||||
|
|
||||||
return plaintext, err
|
|
||||||
}
|
|
224
vendor/github.com/square/go-jose/shared.go
generated
vendored
224
vendor/github.com/square/go-jose/shared.go
generated
vendored
@ -1,224 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright 2014 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 jose
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// KeyAlgorithm represents a key management algorithm.
|
|
||||||
type KeyAlgorithm string
|
|
||||||
|
|
||||||
// SignatureAlgorithm represents a signature (or MAC) algorithm.
|
|
||||||
type SignatureAlgorithm string
|
|
||||||
|
|
||||||
// ContentEncryption represents a content encryption algorithm.
|
|
||||||
type ContentEncryption string
|
|
||||||
|
|
||||||
// CompressionAlgorithm represents an algorithm used for plaintext compression.
|
|
||||||
type CompressionAlgorithm string
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrCryptoFailure represents an error in cryptographic primitive. This
|
|
||||||
// occurs when, for example, a message had an invalid authentication tag or
|
|
||||||
// could not be decrypted.
|
|
||||||
ErrCryptoFailure = errors.New("square/go-jose: error in cryptographic primitive")
|
|
||||||
|
|
||||||
// ErrUnsupportedAlgorithm indicates that a selected algorithm is not
|
|
||||||
// supported. This occurs when trying to instantiate an encrypter for an
|
|
||||||
// algorithm that is not yet implemented.
|
|
||||||
ErrUnsupportedAlgorithm = errors.New("square/go-jose: unknown/unsupported algorithm")
|
|
||||||
|
|
||||||
// ErrUnsupportedKeyType indicates that the given key type/format is not
|
|
||||||
// supported. This occurs when trying to instantiate an encrypter and passing
|
|
||||||
// it a key of an unrecognized type or with unsupported parameters, such as
|
|
||||||
// an RSA private key with more than two primes.
|
|
||||||
ErrUnsupportedKeyType = errors.New("square/go-jose: unsupported key type/format")
|
|
||||||
|
|
||||||
// ErrNotSupported serialization of object is not supported. This occurs when
|
|
||||||
// trying to compact-serialize an object which can't be represented in
|
|
||||||
// compact form.
|
|
||||||
ErrNotSupported = errors.New("square/go-jose: compact serialization not supported for object")
|
|
||||||
|
|
||||||
// ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a
|
|
||||||
// nonce header parameter was included in an unprotected header object.
|
|
||||||
ErrUnprotectedNonce = errors.New("square/go-jose: Nonce parameter included in unprotected header")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Key management algorithms
|
|
||||||
const (
|
|
||||||
RSA1_5 = KeyAlgorithm("RSA1_5") // RSA-PKCS1v1.5
|
|
||||||
RSA_OAEP = KeyAlgorithm("RSA-OAEP") // RSA-OAEP-SHA1
|
|
||||||
RSA_OAEP_256 = KeyAlgorithm("RSA-OAEP-256") // RSA-OAEP-SHA256
|
|
||||||
A128KW = KeyAlgorithm("A128KW") // AES key wrap (128)
|
|
||||||
A192KW = KeyAlgorithm("A192KW") // AES key wrap (192)
|
|
||||||
A256KW = KeyAlgorithm("A256KW") // AES key wrap (256)
|
|
||||||
DIRECT = KeyAlgorithm("dir") // Direct encryption
|
|
||||||
ECDH_ES = KeyAlgorithm("ECDH-ES") // ECDH-ES
|
|
||||||
ECDH_ES_A128KW = KeyAlgorithm("ECDH-ES+A128KW") // ECDH-ES + AES key wrap (128)
|
|
||||||
ECDH_ES_A192KW = KeyAlgorithm("ECDH-ES+A192KW") // ECDH-ES + AES key wrap (192)
|
|
||||||
ECDH_ES_A256KW = KeyAlgorithm("ECDH-ES+A256KW") // ECDH-ES + AES key wrap (256)
|
|
||||||
A128GCMKW = KeyAlgorithm("A128GCMKW") // AES-GCM key wrap (128)
|
|
||||||
A192GCMKW = KeyAlgorithm("A192GCMKW") // AES-GCM key wrap (192)
|
|
||||||
A256GCMKW = KeyAlgorithm("A256GCMKW") // AES-GCM key wrap (256)
|
|
||||||
PBES2_HS256_A128KW = KeyAlgorithm("PBES2-HS256+A128KW") // PBES2 + HMAC-SHA256 + AES key wrap (128)
|
|
||||||
PBES2_HS384_A192KW = KeyAlgorithm("PBES2-HS384+A192KW") // PBES2 + HMAC-SHA384 + AES key wrap (192)
|
|
||||||
PBES2_HS512_A256KW = KeyAlgorithm("PBES2-HS512+A256KW") // PBES2 + HMAC-SHA512 + AES key wrap (256)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Signature algorithms
|
|
||||||
const (
|
|
||||||
HS256 = SignatureAlgorithm("HS256") // HMAC using SHA-256
|
|
||||||
HS384 = SignatureAlgorithm("HS384") // HMAC using SHA-384
|
|
||||||
HS512 = SignatureAlgorithm("HS512") // HMAC using SHA-512
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
// Content encryption algorithms
|
|
||||||
const (
|
|
||||||
A128CBC_HS256 = ContentEncryption("A128CBC-HS256") // AES-CBC + HMAC-SHA256 (128)
|
|
||||||
A192CBC_HS384 = ContentEncryption("A192CBC-HS384") // AES-CBC + HMAC-SHA384 (192)
|
|
||||||
A256CBC_HS512 = ContentEncryption("A256CBC-HS512") // AES-CBC + HMAC-SHA512 (256)
|
|
||||||
A128GCM = ContentEncryption("A128GCM") // AES-GCM (128)
|
|
||||||
A192GCM = ContentEncryption("A192GCM") // AES-GCM (192)
|
|
||||||
A256GCM = ContentEncryption("A256GCM") // AES-GCM (256)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Compression algorithms
|
|
||||||
const (
|
|
||||||
NONE = CompressionAlgorithm("") // No compression
|
|
||||||
DEFLATE = CompressionAlgorithm("DEF") // DEFLATE (RFC 1951)
|
|
||||||
)
|
|
||||||
|
|
||||||
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
|
|
||||||
type rawHeader struct {
|
|
||||||
Alg string `json:"alg,omitempty"`
|
|
||||||
Enc ContentEncryption `json:"enc,omitempty"`
|
|
||||||
Zip CompressionAlgorithm `json:"zip,omitempty"`
|
|
||||||
Crit []string `json:"crit,omitempty"`
|
|
||||||
Apu *byteBuffer `json:"apu,omitempty"`
|
|
||||||
Apv *byteBuffer `json:"apv,omitempty"`
|
|
||||||
Epk *JsonWebKey `json:"epk,omitempty"`
|
|
||||||
Iv *byteBuffer `json:"iv,omitempty"`
|
|
||||||
Tag *byteBuffer `json:"tag,omitempty"`
|
|
||||||
Jwk *JsonWebKey `json:"jwk,omitempty"`
|
|
||||||
Kid string `json:"kid,omitempty"`
|
|
||||||
Nonce string `json:"nonce,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// JoseHeader represents the read-only JOSE header for JWE/JWS objects.
|
|
||||||
type JoseHeader struct {
|
|
||||||
KeyID string
|
|
||||||
JsonWebKey *JsonWebKey
|
|
||||||
Algorithm string
|
|
||||||
Nonce string
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanitized produces a cleaned-up header object from the raw JSON.
|
|
||||||
func (parsed rawHeader) sanitized() JoseHeader {
|
|
||||||
return JoseHeader{
|
|
||||||
KeyID: parsed.Kid,
|
|
||||||
JsonWebKey: parsed.Jwk,
|
|
||||||
Algorithm: parsed.Alg,
|
|
||||||
Nonce: parsed.Nonce,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge headers from src into dst, giving precedence to headers from l.
|
|
||||||
func (dst *rawHeader) merge(src *rawHeader) {
|
|
||||||
if src == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if dst.Alg == "" {
|
|
||||||
dst.Alg = src.Alg
|
|
||||||
}
|
|
||||||
if dst.Enc == "" {
|
|
||||||
dst.Enc = src.Enc
|
|
||||||
}
|
|
||||||
if dst.Zip == "" {
|
|
||||||
dst.Zip = src.Zip
|
|
||||||
}
|
|
||||||
if dst.Crit == nil {
|
|
||||||
dst.Crit = src.Crit
|
|
||||||
}
|
|
||||||
if dst.Crit == nil {
|
|
||||||
dst.Crit = src.Crit
|
|
||||||
}
|
|
||||||
if dst.Apu == nil {
|
|
||||||
dst.Apu = src.Apu
|
|
||||||
}
|
|
||||||
if dst.Apv == nil {
|
|
||||||
dst.Apv = src.Apv
|
|
||||||
}
|
|
||||||
if dst.Epk == nil {
|
|
||||||
dst.Epk = src.Epk
|
|
||||||
}
|
|
||||||
if dst.Iv == nil {
|
|
||||||
dst.Iv = src.Iv
|
|
||||||
}
|
|
||||||
if dst.Tag == nil {
|
|
||||||
dst.Tag = src.Tag
|
|
||||||
}
|
|
||||||
if dst.Kid == "" {
|
|
||||||
dst.Kid = src.Kid
|
|
||||||
}
|
|
||||||
if dst.Jwk == nil {
|
|
||||||
dst.Jwk = src.Jwk
|
|
||||||
}
|
|
||||||
if dst.Nonce == "" {
|
|
||||||
dst.Nonce = src.Nonce
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get JOSE name of curve
|
|
||||||
func curveName(crv elliptic.Curve) (string, error) {
|
|
||||||
switch crv {
|
|
||||||
case elliptic.P256():
|
|
||||||
return "P-256", nil
|
|
||||||
case elliptic.P384():
|
|
||||||
return "P-384", nil
|
|
||||||
case elliptic.P521():
|
|
||||||
return "P-521", nil
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("square/go-jose: unsupported/unknown elliptic curve")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get size of curve in bytes
|
|
||||||
func curveSize(crv elliptic.Curve) int {
|
|
||||||
bits := crv.Params().BitSize
|
|
||||||
|
|
||||||
div := bits / 8
|
|
||||||
mod := bits % 8
|
|
||||||
|
|
||||||
if mod == 0 {
|
|
||||||
return div
|
|
||||||
}
|
|
||||||
|
|
||||||
return div + 1
|
|
||||||
}
|
|
218
vendor/github.com/square/go-jose/signing.go
generated
vendored
218
vendor/github.com/square/go-jose/signing.go
generated
vendored
@ -1,218 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright 2014 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 jose
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/rsa"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NonceSource represents a source of random nonces to go into JWS objects
|
|
||||||
type NonceSource interface {
|
|
||||||
Nonce() (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signer represents a signer which takes a payload and produces a signed JWS object.
|
|
||||||
type Signer interface {
|
|
||||||
Sign(payload []byte) (*JsonWebSignature, error)
|
|
||||||
SetNonceSource(source NonceSource)
|
|
||||||
SetEmbedJwk(embed bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MultiSigner represents a signer which supports multiple recipients.
|
|
||||||
type MultiSigner interface {
|
|
||||||
Sign(payload []byte) (*JsonWebSignature, error)
|
|
||||||
SetNonceSource(source NonceSource)
|
|
||||||
SetEmbedJwk(embed bool)
|
|
||||||
AddRecipient(alg SignatureAlgorithm, signingKey interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type payloadSigner interface {
|
|
||||||
signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type payloadVerifier interface {
|
|
||||||
verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type genericSigner struct {
|
|
||||||
recipients []recipientSigInfo
|
|
||||||
nonceSource NonceSource
|
|
||||||
embedJwk bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type recipientSigInfo struct {
|
|
||||||
sigAlg SignatureAlgorithm
|
|
||||||
keyID string
|
|
||||||
publicKey *JsonWebKey
|
|
||||||
signer payloadSigner
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSigner creates an appropriate signer based on the key type
|
|
||||||
func NewSigner(alg SignatureAlgorithm, signingKey interface{}) (Signer, error) {
|
|
||||||
// NewMultiSigner never fails (currently)
|
|
||||||
signer := NewMultiSigner()
|
|
||||||
|
|
||||||
err := signer.AddRecipient(alg, signingKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return signer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMultiSigner creates a signer for multiple recipients
|
|
||||||
func NewMultiSigner() MultiSigner {
|
|
||||||
return &genericSigner{
|
|
||||||
recipients: []recipientSigInfo{},
|
|
||||||
embedJwk: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newVerifier creates a verifier based on the key type
|
|
||||||
func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
|
|
||||||
switch verificationKey := verificationKey.(type) {
|
|
||||||
case *rsa.PublicKey:
|
|
||||||
return &rsaEncrypterVerifier{
|
|
||||||
publicKey: verificationKey,
|
|
||||||
}, nil
|
|
||||||
case *ecdsa.PublicKey:
|
|
||||||
return &ecEncrypterVerifier{
|
|
||||||
publicKey: verificationKey,
|
|
||||||
}, nil
|
|
||||||
case []byte:
|
|
||||||
return &symmetricMac{
|
|
||||||
key: verificationKey,
|
|
||||||
}, nil
|
|
||||||
case *JsonWebKey:
|
|
||||||
return newVerifier(verificationKey.Key)
|
|
||||||
default:
|
|
||||||
return nil, ErrUnsupportedKeyType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *genericSigner) AddRecipient(alg SignatureAlgorithm, signingKey interface{}) error {
|
|
||||||
recipient, err := makeJWSRecipient(alg, signingKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.recipients = append(ctx.recipients, recipient)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipientSigInfo, error) {
|
|
||||||
switch signingKey := signingKey.(type) {
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
return newRSASigner(alg, signingKey)
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
return newECDSASigner(alg, signingKey)
|
|
||||||
case []byte:
|
|
||||||
return newSymmetricSigner(alg, signingKey)
|
|
||||||
case *JsonWebKey:
|
|
||||||
recipient, err := makeJWSRecipient(alg, signingKey.Key)
|
|
||||||
if err != nil {
|
|
||||||
return recipientSigInfo{}, err
|
|
||||||
}
|
|
||||||
recipient.keyID = signingKey.KeyID
|
|
||||||
return recipient, nil
|
|
||||||
default:
|
|
||||||
return recipientSigInfo{}, ErrUnsupportedKeyType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *genericSigner) Sign(payload []byte) (*JsonWebSignature, error) {
|
|
||||||
obj := &JsonWebSignature{}
|
|
||||||
obj.payload = payload
|
|
||||||
obj.Signatures = make([]Signature, len(ctx.recipients))
|
|
||||||
|
|
||||||
for i, recipient := range ctx.recipients {
|
|
||||||
protected := &rawHeader{
|
|
||||||
Alg: string(recipient.sigAlg),
|
|
||||||
}
|
|
||||||
|
|
||||||
if recipient.publicKey != nil && ctx.embedJwk {
|
|
||||||
protected.Jwk = recipient.publicKey
|
|
||||||
}
|
|
||||||
if recipient.keyID != "" {
|
|
||||||
protected.Kid = recipient.keyID
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.nonceSource != nil {
|
|
||||||
nonce, err := ctx.nonceSource.Nonce()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("square/go-jose: Error generating nonce: %v", err)
|
|
||||||
}
|
|
||||||
protected.Nonce = nonce
|
|
||||||
}
|
|
||||||
|
|
||||||
serializedProtected := mustSerializeJSON(protected)
|
|
||||||
|
|
||||||
input := []byte(fmt.Sprintf("%s.%s",
|
|
||||||
base64URLEncode(serializedProtected),
|
|
||||||
base64URLEncode(payload)))
|
|
||||||
|
|
||||||
signatureInfo, err := recipient.signer.signPayload(input, recipient.sigAlg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
signatureInfo.protected = protected
|
|
||||||
obj.Signatures[i] = signatureInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNonceSource provides or updates a nonce pool to the first recipients.
|
|
||||||
// After this method is called, the signer will consume one nonce per
|
|
||||||
// signature, returning an error it is unable to get a nonce.
|
|
||||||
func (ctx *genericSigner) SetNonceSource(source NonceSource) {
|
|
||||||
ctx.nonceSource = source
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEmbedJwk specifies if the signing key should be embedded in the protected header,
|
|
||||||
// if any. It defaults to 'true'.
|
|
||||||
func (ctx *genericSigner) SetEmbedJwk(embed bool) {
|
|
||||||
ctx.embedJwk = embed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify validates the signature on the object and returns the payload.
|
|
||||||
func (obj JsonWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
|
|
||||||
verifier, err := newVerifier(verificationKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, signature := range obj.Signatures {
|
|
||||||
headers := signature.mergedHeaders()
|
|
||||||
if len(headers.Crit) > 0 {
|
|
||||||
// Unsupported crit header
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
input := obj.computeAuthData(&signature)
|
|
||||||
alg := SignatureAlgorithm(headers.Alg)
|
|
||||||
err := verifier.verifyPayload(input, signature.Signature, alg)
|
|
||||||
if err == nil {
|
|
||||||
return obj.payload, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, ErrCryptoFailure
|
|
||||||
}
|
|
74
vendor/github.com/square/go-jose/utils.go
generated
vendored
74
vendor/github.com/square/go-jose/utils.go
generated
vendored
@ -1,74 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright 2014 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 jose
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadPublicKey loads a public key from PEM/DER-encoded data.
|
|
||||||
func LoadPublicKey(data []byte) (interface{}, error) {
|
|
||||||
input := data
|
|
||||||
|
|
||||||
block, _ := pem.Decode(data)
|
|
||||||
if block != nil {
|
|
||||||
input = block.Bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load SubjectPublicKeyInfo
|
|
||||||
pub, err0 := x509.ParsePKIXPublicKey(input)
|
|
||||||
if err0 == nil {
|
|
||||||
return pub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cert, err1 := x509.ParseCertificate(input)
|
|
||||||
if err1 == nil {
|
|
||||||
return cert.PublicKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("square/go-jose: parse error, got '%s' and '%s'", err0, err1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadPrivateKey loads a private key from PEM/DER-encoded data.
|
|
||||||
func LoadPrivateKey(data []byte) (interface{}, error) {
|
|
||||||
input := data
|
|
||||||
|
|
||||||
block, _ := pem.Decode(data)
|
|
||||||
if block != nil {
|
|
||||||
input = block.Bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
var priv interface{}
|
|
||||||
priv, err0 := x509.ParsePKCS1PrivateKey(input)
|
|
||||||
if err0 == nil {
|
|
||||||
return priv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
priv, err1 := x509.ParsePKCS8PrivateKey(input)
|
|
||||||
if err1 == nil {
|
|
||||||
return priv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
priv, err2 := x509.ParseECPrivateKey(input)
|
|
||||||
if err2 == nil {
|
|
||||||
return priv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("square/go-jose: parse error, got '%s', '%s' and '%s'", err0, err1, err2)
|
|
||||||
}
|
|
@ -8,13 +8,15 @@ matrix:
|
|||||||
- go: tip
|
- go: tip
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.3
|
|
||||||
- 1.4
|
|
||||||
- 1.5
|
- 1.5
|
||||||
- 1.6
|
- 1.6
|
||||||
- 1.7
|
- 1.7
|
||||||
|
- 1.8
|
||||||
|
- 1.9
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
|
go_import_path: gopkg.in/square/go-jose.v2
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- export PATH=$HOME/.local/bin:$PATH
|
- export PATH=$HOME/.local/bin:$PATH
|
||||||
|
|
||||||
@ -26,13 +28,15 @@ before_install:
|
|||||||
- bash .gitcookies.sh || true
|
- bash .gitcookies.sh || true
|
||||||
- go get github.com/wadey/gocovmerge
|
- go get github.com/wadey/gocovmerge
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
|
- go get github.com/stretchr/testify/assert
|
||||||
- go get golang.org/x/tools/cmd/cover || true
|
- go get golang.org/x/tools/cmd/cover || true
|
||||||
- go get code.google.com/p/go.tools/cmd/cover || true
|
- go get code.google.com/p/go.tools/cmd/cover || true
|
||||||
- pip install cram --user `whoami`
|
- pip install cram --user
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- go test . -v -covermode=count -coverprofile=profile.cov
|
- go test . -v -covermode=count -coverprofile=profile.cov
|
||||||
- go test ./cipher -v -covermode=count -coverprofile=cipher/profile.cov
|
- 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
|
- 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
|
||||||
- cd ..
|
- cd ..
|
12
vendor/github.com/square/go-jose/BUILD → vendor/gopkg.in/square/go-jose.v2/BUILD
generated
vendored
12
vendor/github.com/square/go-jose/BUILD → vendor/gopkg.in/square/go-jose.v2/BUILD
generated
vendored
@ -13,13 +13,13 @@ go_library(
|
|||||||
"shared.go",
|
"shared.go",
|
||||||
"signing.go",
|
"signing.go",
|
||||||
"symmetric.go",
|
"symmetric.go",
|
||||||
"utils.go",
|
|
||||||
],
|
],
|
||||||
importpath = "github.com/square/go-jose",
|
importpath = "gopkg.in/square/go-jose.v2",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/square/go-jose/cipher:go_default_library",
|
"//vendor/golang.org/x/crypto/ed25519:go_default_library",
|
||||||
"//vendor/github.com/square/go-jose/json:go_default_library",
|
"//vendor/gopkg.in/square/go-jose.v2/cipher:go_default_library",
|
||||||
|
"//vendor/gopkg.in/square/go-jose.v2/json:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,8 +34,8 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//vendor/github.com/square/go-jose/cipher:all-srcs",
|
"//vendor/gopkg.in/square/go-jose.v2/cipher:all-srcs",
|
||||||
"//vendor/github.com/square/go-jose/json:all-srcs",
|
"//vendor/gopkg.in/square/go-jose.v2/json:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
0
vendor/github.com/square/go-jose/LICENSE → vendor/gopkg.in/square/go-jose.v2/LICENSE
generated
vendored
0
vendor/github.com/square/go-jose/LICENSE → vendor/gopkg.in/square/go-jose.v2/LICENSE
generated
vendored
119
vendor/gopkg.in/square/go-jose.v2/README.md
generated
vendored
Normal file
119
vendor/gopkg.in/square/go-jose.v2/README.md
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# Go JOSE
|
||||||
|
|
||||||
|
[](https://godoc.org/gopkg.in/square/go-jose.v1)
|
||||||
|
[](https://godoc.org/gopkg.in/square/go-jose.v2)
|
||||||
|
[](https://raw.githubusercontent.com/square/go-jose/master/LICENSE)
|
||||||
|
[](https://travis-ci.org/square/go-jose)
|
||||||
|
[](https://coveralls.io/r/square/go-jose)
|
||||||
|
|
||||||
|
Package jose aims to provide an implementation of the Javascript Object Signing
|
||||||
|
and Encryption set of standards. This includes support for JSON Web Encryption,
|
||||||
|
JSON Web Signature, and JSON Web Token standards.
|
||||||
|
|
||||||
|
**Disclaimer**: This library contains encryption software that is subject to
|
||||||
|
the U.S. Export Administration Regulations. You may not export, re-export,
|
||||||
|
transfer or download this code or any part of it in violation of any United
|
||||||
|
States law, directive or regulation. In particular this software may not be
|
||||||
|
exported or re-exported in any form or on any media to Iran, North Sudan,
|
||||||
|
Syria, Cuba, or North Korea, or to denied persons or entities mentioned on any
|
||||||
|
US maintained blocked list.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The implementation follows the
|
||||||
|
[JSON Web Encryption](http://dx.doi.org/10.17487/RFC7516) (RFC 7516),
|
||||||
|
[JSON Web Signature](http://dx.doi.org/10.17487/RFC7515) (RFC 7515), and
|
||||||
|
[JSON Web Token](http://dx.doi.org/10.17487/RFC7519) (RFC 7519).
|
||||||
|
Tables of supported algorithms are shown below. The library supports both
|
||||||
|
the compact and full serialization formats, and has optional support for
|
||||||
|
multiple recipients. It also comes with a small command-line utility
|
||||||
|
([`jose-util`](https://github.com/square/go-jose/tree/v2/jose-util))
|
||||||
|
for dealing with JOSE messages in a shell.
|
||||||
|
|
||||||
|
**Note**: We use a forked version of the `encoding/json` package from the Go
|
||||||
|
standard library which uses case-sensitive matching for member names (instead
|
||||||
|
of [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html)).
|
||||||
|
This is to avoid differences in interpretation of messages between go-jose and
|
||||||
|
libraries in other languages.
|
||||||
|
|
||||||
|
### Versions
|
||||||
|
|
||||||
|
We use [gopkg.in](https://gopkg.in) for versioning.
|
||||||
|
|
||||||
|
[Version 1](https://gopkg.in/square/go-jose.v1) is the old stable version:
|
||||||
|
|
||||||
|
import "gopkg.in/square/go-jose.v1"
|
||||||
|
|
||||||
|
[Version 2](https://gopkg.in/square/go-jose.v2) is for new development:
|
||||||
|
|
||||||
|
import "gopkg.in/square/go-jose.v2"
|
||||||
|
|
||||||
|
The interface for [go-jose.v1](https://gopkg.in/square/go-jose.v1) will remain
|
||||||
|
backwards compatible. No new feature development will take place on the `v1` branch,
|
||||||
|
however bug fixes and security fixes will be backported.
|
||||||
|
|
||||||
|
The interface for [go-jose.v2](https://gopkg.in/square/go-jose.v2) is mostly
|
||||||
|
stable, but we suggest pinning to a particular revision for now as we still reserve
|
||||||
|
the right to make changes. New feature development happens on this branch.
|
||||||
|
|
||||||
|
New in [go-jose.v2](https://gopkg.in/square/go-jose.v2) is a
|
||||||
|
[jwt](https://godoc.org/gopkg.in/square/go-jose.v2/jwt) sub-package
|
||||||
|
contributed by [@shaxbee](https://github.com/shaxbee).
|
||||||
|
|
||||||
|
### Supported algorithms
|
||||||
|
|
||||||
|
See below for a table of supported algorithms. Algorithm identifiers match
|
||||||
|
the names in the [JSON Web Algorithms](http://dx.doi.org/10.17487/RFC7518)
|
||||||
|
standard where possible. The Godoc reference has a list of constants.
|
||||||
|
|
||||||
|
Key encryption | Algorithm identifier(s)
|
||||||
|
:------------------------- | :------------------------------
|
||||||
|
RSA-PKCS#1v1.5 | RSA1_5
|
||||||
|
RSA-OAEP | RSA-OAEP, RSA-OAEP-256
|
||||||
|
AES key wrap | A128KW, A192KW, A256KW
|
||||||
|
AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW
|
||||||
|
ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW
|
||||||
|
ECDH-ES (direct) | ECDH-ES<sup>1</sup>
|
||||||
|
Direct encryption | dir<sup>1</sup>
|
||||||
|
|
||||||
|
<sup>1. Not supported in multi-recipient mode</sup>
|
||||||
|
|
||||||
|
Signing / MAC | Algorithm identifier(s)
|
||||||
|
:------------------------- | :------------------------------
|
||||||
|
RSASSA-PKCS#1v1.5 | RS256, RS384, RS512
|
||||||
|
RSASSA-PSS | PS256, PS384, PS512
|
||||||
|
HMAC | HS256, HS384, HS512
|
||||||
|
ECDSA | ES256, ES384, ES512
|
||||||
|
|
||||||
|
Content encryption | Algorithm identifier(s)
|
||||||
|
:------------------------- | :------------------------------
|
||||||
|
AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512
|
||||||
|
AES-GCM | A128GCM, A192GCM, A256GCM
|
||||||
|
|
||||||
|
Compression | Algorithm identifiers(s)
|
||||||
|
:------------------------- | -------------------------------
|
||||||
|
DEFLATE (RFC 1951) | DEF
|
||||||
|
|
||||||
|
### Supported key types
|
||||||
|
|
||||||
|
See below for a table of supported key types. These are understood by the
|
||||||
|
library, and can be passed to corresponding functions such as `NewEncrypter` or
|
||||||
|
`NewSigner`. Each of these keys can also be wrapped in a JWK if desired, which
|
||||||
|
allows attaching a key id.
|
||||||
|
|
||||||
|
Algorithm(s) | Corresponding types
|
||||||
|
:------------------------- | -------------------------------
|
||||||
|
RSA | *[rsa.PublicKey](http://golang.org/pkg/crypto/rsa/#PublicKey), *[rsa.PrivateKey](http://golang.org/pkg/crypto/rsa/#PrivateKey)
|
||||||
|
ECDH, ECDSA | *[ecdsa.PublicKey](http://golang.org/pkg/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](http://golang.org/pkg/crypto/ecdsa/#PrivateKey)
|
||||||
|
AES, HMAC | []byte
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
[](https://godoc.org/gopkg.in/square/go-jose.v1)
|
||||||
|
[](https://godoc.org/gopkg.in/square/go-jose.v2)
|
||||||
|
|
||||||
|
Examples can be found in the Godoc
|
||||||
|
reference for this package. The
|
||||||
|
[`jose-util`](https://github.com/square/go-jose/tree/v2/jose-util)
|
||||||
|
subdirectory also contains a small command-line utility which might be useful
|
||||||
|
as an example.
|
@ -28,7 +28,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/square/go-jose/cipher"
|
"golang.org/x/crypto/ed25519"
|
||||||
|
"gopkg.in/square/go-jose.v2/cipher"
|
||||||
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A generic RSA-based encrypter/verifier
|
// A generic RSA-based encrypter/verifier
|
||||||
@ -46,6 +48,10 @@ type ecEncrypterVerifier struct {
|
|||||||
publicKey *ecdsa.PublicKey
|
publicKey *ecdsa.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type edEncrypterVerifier struct {
|
||||||
|
publicKey ed25519.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
// A key generator for ECDH-ES
|
// A key generator for ECDH-ES
|
||||||
type ecKeyGenerator struct {
|
type ecKeyGenerator struct {
|
||||||
size int
|
size int
|
||||||
@ -58,6 +64,10 @@ type ecDecrypterSigner struct {
|
|||||||
privateKey *ecdsa.PrivateKey
|
privateKey *ecdsa.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type edDecrypterSigner struct {
|
||||||
|
privateKey ed25519.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
// newRSARecipient creates recipientKeyInfo based on the given key.
|
// newRSARecipient creates recipientKeyInfo based on the given key.
|
||||||
func newRSARecipient(keyAlg KeyAlgorithm, publicKey *rsa.PublicKey) (recipientKeyInfo, error) {
|
func newRSARecipient(keyAlg KeyAlgorithm, publicKey *rsa.PublicKey) (recipientKeyInfo, error) {
|
||||||
// Verify that key management algorithm is supported by this encrypter
|
// Verify that key management algorithm is supported by this encrypter
|
||||||
@ -94,7 +104,7 @@ func newRSASigner(sigAlg SignatureAlgorithm, privateKey *rsa.PrivateKey) (recipi
|
|||||||
|
|
||||||
return recipientSigInfo{
|
return recipientSigInfo{
|
||||||
sigAlg: sigAlg,
|
sigAlg: sigAlg,
|
||||||
publicKey: &JsonWebKey{
|
publicKey: &JSONWebKey{
|
||||||
Key: &privateKey.PublicKey,
|
Key: &privateKey.PublicKey,
|
||||||
},
|
},
|
||||||
signer: &rsaDecrypterSigner{
|
signer: &rsaDecrypterSigner{
|
||||||
@ -103,6 +113,25 @@ func newRSASigner(sigAlg SignatureAlgorithm, privateKey *rsa.PrivateKey) (recipi
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newEd25519Signer(sigAlg SignatureAlgorithm, privateKey ed25519.PrivateKey) (recipientSigInfo, error) {
|
||||||
|
if sigAlg != EdDSA {
|
||||||
|
return recipientSigInfo{}, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
if privateKey == nil {
|
||||||
|
return recipientSigInfo{}, errors.New("invalid private key")
|
||||||
|
}
|
||||||
|
return recipientSigInfo{
|
||||||
|
sigAlg: sigAlg,
|
||||||
|
publicKey: &JSONWebKey{
|
||||||
|
Key: privateKey.Public(),
|
||||||
|
},
|
||||||
|
signer: &edDecrypterSigner{
|
||||||
|
privateKey: privateKey,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// newECDHRecipient creates recipientKeyInfo based on the given key.
|
// newECDHRecipient creates recipientKeyInfo based on the given key.
|
||||||
func newECDHRecipient(keyAlg KeyAlgorithm, publicKey *ecdsa.PublicKey) (recipientKeyInfo, error) {
|
func newECDHRecipient(keyAlg KeyAlgorithm, publicKey *ecdsa.PublicKey) (recipientKeyInfo, error) {
|
||||||
// Verify that key management algorithm is supported by this encrypter
|
// Verify that key management algorithm is supported by this encrypter
|
||||||
@ -139,7 +168,7 @@ func newECDSASigner(sigAlg SignatureAlgorithm, privateKey *ecdsa.PrivateKey) (re
|
|||||||
|
|
||||||
return recipientSigInfo{
|
return recipientSigInfo{
|
||||||
sigAlg: sigAlg,
|
sigAlg: sigAlg,
|
||||||
publicKey: &JsonWebKey{
|
publicKey: &JSONWebKey{
|
||||||
Key: &privateKey.PublicKey,
|
Key: &privateKey.PublicKey,
|
||||||
},
|
},
|
||||||
signer: &ecDecrypterSigner{
|
signer: &ecDecrypterSigner{
|
||||||
@ -178,7 +207,7 @@ func (ctx rsaEncrypterVerifier) encrypt(cek []byte, alg KeyAlgorithm) ([]byte, e
|
|||||||
|
|
||||||
// Decrypt the given payload and return the content encryption key.
|
// Decrypt the given payload and return the content encryption key.
|
||||||
func (ctx rsaDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
|
func (ctx rsaDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
|
||||||
return ctx.decrypt(recipient.encryptedKey, KeyAlgorithm(headers.Alg), generator)
|
return ctx.decrypt(recipient.encryptedKey, headers.getAlgorithm(), generator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt the given payload. Based on the key encryption algorithm,
|
// Decrypt the given payload. Based on the key encryption algorithm,
|
||||||
@ -366,10 +395,15 @@ func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
|
|||||||
|
|
||||||
out := josecipher.DeriveECDHES(ctx.algID, []byte{}, []byte{}, priv, ctx.publicKey, ctx.size)
|
out := josecipher.DeriveECDHES(ctx.algID, []byte{}, []byte{}, priv, ctx.publicKey, ctx.size)
|
||||||
|
|
||||||
|
b, err := json.Marshal(&JSONWebKey{
|
||||||
|
Key: &priv.PublicKey,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
headers := rawHeader{
|
headers := rawHeader{
|
||||||
Epk: &JsonWebKey{
|
headerEPK: makeRawMessage(b),
|
||||||
Key: &priv.PublicKey,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return out, headers, nil
|
return out, headers, nil
|
||||||
@ -377,11 +411,15 @@ func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
|
|||||||
|
|
||||||
// Decrypt the given payload and return the content encryption key.
|
// Decrypt the given payload and return the content encryption key.
|
||||||
func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
|
func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
|
||||||
if headers.Epk == nil {
|
epk, err := headers.getEPK()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("square/go-jose: invalid epk header")
|
||||||
|
}
|
||||||
|
if epk == nil {
|
||||||
return nil, errors.New("square/go-jose: missing epk header")
|
return nil, errors.New("square/go-jose: missing epk header")
|
||||||
}
|
}
|
||||||
|
|
||||||
publicKey, ok := headers.Epk.Key.(*ecdsa.PublicKey)
|
publicKey, ok := epk.Key.(*ecdsa.PublicKey)
|
||||||
if publicKey == nil || !ok {
|
if publicKey == nil || !ok {
|
||||||
return nil, errors.New("square/go-jose: invalid epk header")
|
return nil, errors.New("square/go-jose: invalid epk header")
|
||||||
}
|
}
|
||||||
@ -390,19 +428,26 @@ func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientI
|
|||||||
return nil, errors.New("square/go-jose: invalid public key in epk header")
|
return nil, errors.New("square/go-jose: invalid public key in epk header")
|
||||||
}
|
}
|
||||||
|
|
||||||
apuData := headers.Apu.bytes()
|
apuData, err := headers.getAPU()
|
||||||
apvData := headers.Apv.bytes()
|
if err != nil {
|
||||||
|
return nil, errors.New("square/go-jose: invalid apu header")
|
||||||
|
}
|
||||||
|
apvData, err := headers.getAPV()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("square/go-jose: invalid apv header")
|
||||||
|
}
|
||||||
|
|
||||||
deriveKey := func(algID string, size int) []byte {
|
deriveKey := func(algID string, size int) []byte {
|
||||||
return josecipher.DeriveECDHES(algID, apuData, apvData, ctx.privateKey, publicKey, size)
|
return josecipher.DeriveECDHES(algID, apuData.bytes(), apvData.bytes(), ctx.privateKey, publicKey, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
var keySize int
|
var keySize int
|
||||||
|
|
||||||
switch KeyAlgorithm(headers.Alg) {
|
algorithm := headers.getAlgorithm()
|
||||||
|
switch algorithm {
|
||||||
case ECDH_ES:
|
case ECDH_ES:
|
||||||
// ECDH-ES uses direct key agreement, no key unwrapping necessary.
|
// ECDH-ES uses direct key agreement, no key unwrapping necessary.
|
||||||
return deriveKey(string(headers.Enc), generator.keySize()), nil
|
return deriveKey(string(headers.getEncryption()), generator.keySize()), nil
|
||||||
case ECDH_ES_A128KW:
|
case ECDH_ES_A128KW:
|
||||||
keySize = 16
|
keySize = 16
|
||||||
case ECDH_ES_A192KW:
|
case ECDH_ES_A192KW:
|
||||||
@ -413,7 +458,7 @@ func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientI
|
|||||||
return nil, ErrUnsupportedAlgorithm
|
return nil, ErrUnsupportedAlgorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
key := deriveKey(headers.Alg, keySize)
|
key := deriveKey(string(algorithm), keySize)
|
||||||
block, err := aes.NewCipher(key)
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -421,6 +466,32 @@ func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientI
|
|||||||
|
|
||||||
return josecipher.KeyUnwrap(block, recipient.encryptedKey)
|
return josecipher.KeyUnwrap(block, recipient.encryptedKey)
|
||||||
}
|
}
|
||||||
|
func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
|
||||||
|
if alg != EdDSA {
|
||||||
|
return Signature{}, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := ctx.privateKey.Sign(randReader, payload, crypto.Hash(0))
|
||||||
|
if err != nil {
|
||||||
|
return Signature{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Signature{
|
||||||
|
Signature: sig,
|
||||||
|
protected: &rawHeader{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx edEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
|
||||||
|
if alg != EdDSA {
|
||||||
|
return ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
ok := ed25519.Verify(ctx.publicKey, payload, signature)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("square/go-jose: ed25519 signature failed to verify")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Sign the given payload
|
// Sign the given payload
|
||||||
func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
|
func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
|
||||||
@ -457,7 +528,7 @@ func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm)
|
|||||||
|
|
||||||
keyBytes := curveBits / 8
|
keyBytes := curveBits / 8
|
||||||
if curveBits%8 > 0 {
|
if curveBits%8 > 0 {
|
||||||
keyBytes += 1
|
keyBytes++
|
||||||
}
|
}
|
||||||
|
|
||||||
// We serialize the outpus (r and s) into big-endian byte arrays and pad
|
// We serialize the outpus (r and s) into big-endian byte arrays and pad
|
@ -8,7 +8,7 @@ go_library(
|
|||||||
"ecdh_es.go",
|
"ecdh_es.go",
|
||||||
"key_wrap.go",
|
"key_wrap.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/square/go-jose/cipher",
|
importpath = "gopkg.in/square/go-jose.v2/cipher",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
@ -28,7 +28,7 @@ import (
|
|||||||
// size may be at most 1<<16 bytes (64 KiB).
|
// size may be at most 1<<16 bytes (64 KiB).
|
||||||
func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, size int) []byte {
|
func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, size int) []byte {
|
||||||
if size > 1<<16 {
|
if size > 1<<16 {
|
||||||
panic("ECDH-ES output size too large, must be less than 1<<16")
|
panic("ECDH-ES output size too large, must be less than or equal to 1<<16")
|
||||||
}
|
}
|
||||||
|
|
||||||
// algId, partyUInfo, partyVInfo inputs must be prefixed with the length
|
// algId, partyUInfo, partyVInfo inputs must be prefixed with the length
|
510
vendor/gopkg.in/square/go-jose.v2/crypter.go
generated
vendored
Normal file
510
vendor/gopkg.in/square/go-jose.v2/crypter.go
generated
vendored
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2014 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 jose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encrypter represents an encrypter which produces an encrypted JWE object.
|
||||||
|
type Encrypter interface {
|
||||||
|
Encrypt(plaintext []byte) (*JSONWebEncryption, error)
|
||||||
|
EncryptWithAuthData(plaintext []byte, aad []byte) (*JSONWebEncryption, error)
|
||||||
|
Options() EncrypterOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// A generic content cipher
|
||||||
|
type contentCipher interface {
|
||||||
|
keySize() int
|
||||||
|
encrypt(cek []byte, aad, plaintext []byte) (*aeadParts, error)
|
||||||
|
decrypt(cek []byte, aad []byte, parts *aeadParts) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A key generator (for generating/getting a CEK)
|
||||||
|
type keyGenerator interface {
|
||||||
|
keySize() int
|
||||||
|
genKey() ([]byte, rawHeader, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A generic key encrypter
|
||||||
|
type keyEncrypter interface {
|
||||||
|
encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) // Encrypt a key
|
||||||
|
}
|
||||||
|
|
||||||
|
// A generic key decrypter
|
||||||
|
type keyDecrypter interface {
|
||||||
|
decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) // Decrypt a key
|
||||||
|
}
|
||||||
|
|
||||||
|
// A generic encrypter based on the given key encrypter and content cipher.
|
||||||
|
type genericEncrypter struct {
|
||||||
|
contentAlg ContentEncryption
|
||||||
|
compressionAlg CompressionAlgorithm
|
||||||
|
cipher contentCipher
|
||||||
|
recipients []recipientKeyInfo
|
||||||
|
keyGenerator keyGenerator
|
||||||
|
extraHeaders map[HeaderKey]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type recipientKeyInfo struct {
|
||||||
|
keyID string
|
||||||
|
keyAlg KeyAlgorithm
|
||||||
|
keyEncrypter keyEncrypter
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncrypterOptions represents options that can be set on new encrypters.
|
||||||
|
type EncrypterOptions struct {
|
||||||
|
Compression CompressionAlgorithm
|
||||||
|
|
||||||
|
// Optional map of additional keys to be inserted into the protected header
|
||||||
|
// of a JWS object. Some specifications which make use of JWS like to insert
|
||||||
|
// additional values here. All values must be JSON-serializable.
|
||||||
|
ExtraHeaders map[HeaderKey]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it
|
||||||
|
// if necessary. It returns itself and so can be used in a fluent style.
|
||||||
|
func (eo *EncrypterOptions) WithHeader(k HeaderKey, v interface{}) *EncrypterOptions {
|
||||||
|
if eo.ExtraHeaders == nil {
|
||||||
|
eo.ExtraHeaders = map[HeaderKey]interface{}{}
|
||||||
|
}
|
||||||
|
eo.ExtraHeaders[k] = v
|
||||||
|
return eo
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContentType adds a content type ("cty") header and returns the updated
|
||||||
|
// EncrypterOptions.
|
||||||
|
func (eo *EncrypterOptions) WithContentType(contentType ContentType) *EncrypterOptions {
|
||||||
|
return eo.WithHeader(HeaderContentType, contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithType adds a type ("typ") header and returns the updated EncrypterOptions.
|
||||||
|
func (eo *EncrypterOptions) WithType(typ ContentType) *EncrypterOptions {
|
||||||
|
return eo.WithHeader(HeaderType, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recipient represents an algorithm/key to encrypt messages to.
|
||||||
|
type Recipient struct {
|
||||||
|
Algorithm KeyAlgorithm
|
||||||
|
Key interface{}
|
||||||
|
KeyID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncrypter creates an appropriate encrypter based on the key type
|
||||||
|
func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions) (Encrypter, error) {
|
||||||
|
encrypter := &genericEncrypter{
|
||||||
|
contentAlg: enc,
|
||||||
|
recipients: []recipientKeyInfo{},
|
||||||
|
cipher: getContentCipher(enc),
|
||||||
|
}
|
||||||
|
if opts != nil {
|
||||||
|
encrypter.compressionAlg = opts.Compression
|
||||||
|
encrypter.extraHeaders = opts.ExtraHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
if encrypter.cipher == nil {
|
||||||
|
return nil, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyID string
|
||||||
|
var rawKey interface{}
|
||||||
|
switch encryptionKey := rcpt.Key.(type) {
|
||||||
|
case JSONWebKey:
|
||||||
|
keyID, rawKey = encryptionKey.KeyID, encryptionKey.Key
|
||||||
|
case *JSONWebKey:
|
||||||
|
keyID, rawKey = encryptionKey.KeyID, encryptionKey.Key
|
||||||
|
default:
|
||||||
|
rawKey = encryptionKey
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rcpt.Algorithm {
|
||||||
|
case DIRECT:
|
||||||
|
// Direct encryption mode must be treated differently
|
||||||
|
if reflect.TypeOf(rawKey) != reflect.TypeOf([]byte{}) {
|
||||||
|
return nil, ErrUnsupportedKeyType
|
||||||
|
}
|
||||||
|
encrypter.keyGenerator = staticKeyGenerator{
|
||||||
|
key: rawKey.([]byte),
|
||||||
|
}
|
||||||
|
recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, rawKey.([]byte))
|
||||||
|
recipientInfo.keyID = keyID
|
||||||
|
if rcpt.KeyID != "" {
|
||||||
|
recipientInfo.keyID = rcpt.KeyID
|
||||||
|
}
|
||||||
|
encrypter.recipients = []recipientKeyInfo{recipientInfo}
|
||||||
|
return encrypter, nil
|
||||||
|
case ECDH_ES:
|
||||||
|
// ECDH-ES (w/o key wrapping) is similar to DIRECT mode
|
||||||
|
typeOf := reflect.TypeOf(rawKey)
|
||||||
|
if typeOf != reflect.TypeOf(&ecdsa.PublicKey{}) {
|
||||||
|
return nil, ErrUnsupportedKeyType
|
||||||
|
}
|
||||||
|
encrypter.keyGenerator = ecKeyGenerator{
|
||||||
|
size: encrypter.cipher.keySize(),
|
||||||
|
algID: string(enc),
|
||||||
|
publicKey: rawKey.(*ecdsa.PublicKey),
|
||||||
|
}
|
||||||
|
recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, rawKey.(*ecdsa.PublicKey))
|
||||||
|
recipientInfo.keyID = keyID
|
||||||
|
if rcpt.KeyID != "" {
|
||||||
|
recipientInfo.keyID = rcpt.KeyID
|
||||||
|
}
|
||||||
|
encrypter.recipients = []recipientKeyInfo{recipientInfo}
|
||||||
|
return encrypter, nil
|
||||||
|
default:
|
||||||
|
// Can just add a standard recipient
|
||||||
|
encrypter.keyGenerator = randomKeyGenerator{
|
||||||
|
size: encrypter.cipher.keySize(),
|
||||||
|
}
|
||||||
|
err := encrypter.addRecipient(rcpt)
|
||||||
|
return encrypter, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMultiEncrypter creates a multi-encrypter based on the given parameters
|
||||||
|
func NewMultiEncrypter(enc ContentEncryption, rcpts []Recipient, opts *EncrypterOptions) (Encrypter, error) {
|
||||||
|
cipher := getContentCipher(enc)
|
||||||
|
|
||||||
|
if cipher == nil {
|
||||||
|
return nil, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
if rcpts == nil || len(rcpts) == 0 {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: recipients is nil or empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypter := &genericEncrypter{
|
||||||
|
contentAlg: enc,
|
||||||
|
recipients: []recipientKeyInfo{},
|
||||||
|
cipher: cipher,
|
||||||
|
keyGenerator: randomKeyGenerator{
|
||||||
|
size: cipher.keySize(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts != nil {
|
||||||
|
encrypter.compressionAlg = opts.Compression
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, recipient := range rcpts {
|
||||||
|
err := encrypter.addRecipient(recipient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encrypter, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *genericEncrypter) addRecipient(recipient Recipient) (err error) {
|
||||||
|
var recipientInfo recipientKeyInfo
|
||||||
|
|
||||||
|
switch recipient.Algorithm {
|
||||||
|
case DIRECT, ECDH_ES:
|
||||||
|
return fmt.Errorf("square/go-jose: key algorithm '%s' not supported in multi-recipient mode", recipient.Algorithm)
|
||||||
|
}
|
||||||
|
|
||||||
|
recipientInfo, err = makeJWERecipient(recipient.Algorithm, recipient.Key)
|
||||||
|
if recipient.KeyID != "" {
|
||||||
|
recipientInfo.keyID = recipient.KeyID
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
ctx.recipients = append(ctx.recipients, recipientInfo)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKeyInfo, error) {
|
||||||
|
switch encryptionKey := encryptionKey.(type) {
|
||||||
|
case *rsa.PublicKey:
|
||||||
|
return newRSARecipient(alg, encryptionKey)
|
||||||
|
case *ecdsa.PublicKey:
|
||||||
|
return newECDHRecipient(alg, encryptionKey)
|
||||||
|
case []byte:
|
||||||
|
return newSymmetricRecipient(alg, encryptionKey)
|
||||||
|
case *JSONWebKey:
|
||||||
|
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
|
||||||
|
recipient.keyID = encryptionKey.KeyID
|
||||||
|
return recipient, err
|
||||||
|
default:
|
||||||
|
return recipientKeyInfo{}, ErrUnsupportedKeyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDecrypter creates an appropriate decrypter based on the key type
|
||||||
|
func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) {
|
||||||
|
switch decryptionKey := decryptionKey.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
return &rsaDecrypterSigner{
|
||||||
|
privateKey: decryptionKey,
|
||||||
|
}, nil
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
return &ecDecrypterSigner{
|
||||||
|
privateKey: decryptionKey,
|
||||||
|
}, nil
|
||||||
|
case []byte:
|
||||||
|
return &symmetricKeyCipher{
|
||||||
|
key: decryptionKey,
|
||||||
|
}, nil
|
||||||
|
case JSONWebKey:
|
||||||
|
return newDecrypter(decryptionKey.Key)
|
||||||
|
case *JSONWebKey:
|
||||||
|
return newDecrypter(decryptionKey.Key)
|
||||||
|
default:
|
||||||
|
return nil, ErrUnsupportedKeyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of encrypt method producing a JWE object.
|
||||||
|
func (ctx *genericEncrypter) Encrypt(plaintext []byte) (*JSONWebEncryption, error) {
|
||||||
|
return ctx.EncryptWithAuthData(plaintext, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of encrypt method producing a JWE object.
|
||||||
|
func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JSONWebEncryption, error) {
|
||||||
|
obj := &JSONWebEncryption{}
|
||||||
|
obj.aad = aad
|
||||||
|
|
||||||
|
obj.protected = &rawHeader{}
|
||||||
|
err := obj.protected.set(headerEncryption, ctx.contentAlg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.recipients = make([]recipientInfo, len(ctx.recipients))
|
||||||
|
|
||||||
|
if len(ctx.recipients) == 0 {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: no recipients to encrypt to")
|
||||||
|
}
|
||||||
|
|
||||||
|
cek, headers, err := ctx.keyGenerator.genKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.protected.merge(&headers)
|
||||||
|
|
||||||
|
for i, info := range ctx.recipients {
|
||||||
|
recipient, err := info.keyEncrypter.encryptKey(cek, info.keyAlg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = recipient.header.set(headerAlgorithm, info.keyAlg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.keyID != "" {
|
||||||
|
err = recipient.header.set(headerKeyID, info.keyID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.recipients[i] = recipient
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ctx.recipients) == 1 {
|
||||||
|
// Move per-recipient headers into main protected header if there's
|
||||||
|
// only a single recipient.
|
||||||
|
obj.protected.merge(obj.recipients[0].header)
|
||||||
|
obj.recipients[0].header = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.compressionAlg != NONE {
|
||||||
|
plaintext, err = compress(ctx.compressionAlg, plaintext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = obj.protected.set(headerCompression, ctx.compressionAlg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range ctx.extraHeaders {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
(*obj.protected)[k] = makeRawMessage(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
authData := obj.computeAuthData()
|
||||||
|
parts, err := ctx.cipher.encrypt(cek, authData, plaintext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.iv = parts.iv
|
||||||
|
obj.ciphertext = parts.ciphertext
|
||||||
|
obj.tag = parts.tag
|
||||||
|
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *genericEncrypter) Options() EncrypterOptions {
|
||||||
|
return EncrypterOptions{
|
||||||
|
Compression: ctx.compressionAlg,
|
||||||
|
ExtraHeaders: ctx.extraHeaders,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt and validate the object and return the plaintext. Note that this
|
||||||
|
// function does not support multi-recipient, if you desire multi-recipient
|
||||||
|
// decryption use DecryptMulti instead.
|
||||||
|
func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) {
|
||||||
|
headers := obj.mergedHeaders(nil)
|
||||||
|
|
||||||
|
if len(obj.recipients) > 1 {
|
||||||
|
return nil, errors.New("square/go-jose: too many recipients in payload; expecting only one")
|
||||||
|
}
|
||||||
|
|
||||||
|
critical, err := headers.getCritical()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: invalid crit header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(critical) > 0 {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: unsupported crit header")
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypter, err := newDecrypter(decryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher := getContentCipher(headers.getEncryption())
|
||||||
|
if cipher == nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: unsupported enc value '%s'", string(headers.getEncryption()))
|
||||||
|
}
|
||||||
|
|
||||||
|
generator := randomKeyGenerator{
|
||||||
|
size: cipher.keySize(),
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := &aeadParts{
|
||||||
|
iv: obj.iv,
|
||||||
|
ciphertext: obj.ciphertext,
|
||||||
|
tag: obj.tag,
|
||||||
|
}
|
||||||
|
|
||||||
|
authData := obj.computeAuthData()
|
||||||
|
|
||||||
|
var plaintext []byte
|
||||||
|
recipient := obj.recipients[0]
|
||||||
|
recipientHeaders := obj.mergedHeaders(&recipient)
|
||||||
|
|
||||||
|
cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator)
|
||||||
|
if err == nil {
|
||||||
|
// Found a valid CEK -- let's try to decrypt.
|
||||||
|
plaintext, err = cipher.decrypt(cek, authData, parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
if plaintext == nil {
|
||||||
|
return nil, ErrCryptoFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "zip" header parameter may only be present in the protected header.
|
||||||
|
if comp := obj.protected.getCompression(); comp != "" {
|
||||||
|
plaintext, err = decompress(comp, plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
return plaintext, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMulti decrypts and validates the object and returns the plaintexts,
|
||||||
|
// with support for multiple recipients. It returns the index of the recipient
|
||||||
|
// for which the decryption was successful, the merged headers for that recipient,
|
||||||
|
// and the plaintext.
|
||||||
|
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
|
||||||
|
globalHeaders := obj.mergedHeaders(nil)
|
||||||
|
|
||||||
|
critical, err := globalHeaders.getCritical()
|
||||||
|
if err != nil {
|
||||||
|
return -1, Header{}, nil, fmt.Errorf("square/go-jose: invalid crit header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(critical) > 0 {
|
||||||
|
return -1, Header{}, nil, fmt.Errorf("square/go-jose: unsupported crit header")
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypter, err := newDecrypter(decryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
return -1, Header{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryption := globalHeaders.getEncryption()
|
||||||
|
cipher := getContentCipher(encryption)
|
||||||
|
if cipher == nil {
|
||||||
|
return -1, Header{}, nil, fmt.Errorf("square/go-jose: unsupported enc value '%s'", string(encryption))
|
||||||
|
}
|
||||||
|
|
||||||
|
generator := randomKeyGenerator{
|
||||||
|
size: cipher.keySize(),
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := &aeadParts{
|
||||||
|
iv: obj.iv,
|
||||||
|
ciphertext: obj.ciphertext,
|
||||||
|
tag: obj.tag,
|
||||||
|
}
|
||||||
|
|
||||||
|
authData := obj.computeAuthData()
|
||||||
|
|
||||||
|
index := -1
|
||||||
|
var plaintext []byte
|
||||||
|
var headers rawHeader
|
||||||
|
|
||||||
|
for i, recipient := range obj.recipients {
|
||||||
|
recipientHeaders := obj.mergedHeaders(&recipient)
|
||||||
|
|
||||||
|
cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator)
|
||||||
|
if err == nil {
|
||||||
|
// Found a valid CEK -- let's try to decrypt.
|
||||||
|
plaintext, err = cipher.decrypt(cek, authData, parts)
|
||||||
|
if err == nil {
|
||||||
|
index = i
|
||||||
|
headers = recipientHeaders
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if plaintext == nil || err != nil {
|
||||||
|
return -1, Header{}, nil, ErrCryptoFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "zip" header parameter may only be present in the protected header.
|
||||||
|
if comp := obj.protected.getCompression(); comp != "" {
|
||||||
|
plaintext, err = decompress(comp, plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitized, err := headers.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return -1, Header{}, nil, fmt.Errorf("square/go-jose: failed to sanitize header: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return index, sanitized, plaintext, err
|
||||||
|
}
|
9
vendor/github.com/square/go-jose/doc.go → vendor/gopkg.in/square/go-jose.v2/doc.go
generated
vendored
9
vendor/github.com/square/go-jose/doc.go → vendor/gopkg.in/square/go-jose.v2/doc.go
generated
vendored
@ -17,10 +17,11 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Package jose aims to provide an implementation of the Javascript Object Signing
|
Package jose aims to provide an implementation of the Javascript Object Signing
|
||||||
and Encryption set of standards. For the moment, it mainly focuses on
|
and Encryption set of standards. It implements encryption and signing based on
|
||||||
encryption and signing based on the JSON Web Encryption and JSON Web Signature
|
the JSON Web Encryption and JSON Web Signature standards, with optional JSON
|
||||||
standards. The library supports both the compact and full serialization
|
Web Token support available in a sub-package. The library supports both the
|
||||||
formats, and has optional support for multiple recipients.
|
compact and full serialization formats, and has optional support for multiple
|
||||||
|
recipients.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package jose
|
package jose
|
@ -21,29 +21,14 @@ import (
|
|||||||
"compress/flate"
|
"compress/flate"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/square/go-jose/json"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var stripWhitespaceRegex = regexp.MustCompile("\\s")
|
var stripWhitespaceRegex = regexp.MustCompile("\\s")
|
||||||
|
|
||||||
// Url-safe base64 encode that strips padding
|
|
||||||
func base64URLEncode(data []byte) string {
|
|
||||||
var result = base64.URLEncoding.EncodeToString(data)
|
|
||||||
return strings.TrimRight(result, "=")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Url-safe base64 decoder that adds padding
|
|
||||||
func base64URLDecode(data string) ([]byte, error) {
|
|
||||||
var missing = (4 - len(data)%4) % 4
|
|
||||||
data += strings.Repeat("=", missing)
|
|
||||||
return base64.URLEncoding.DecodeString(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to serialize known-good objects.
|
// Helper function to serialize known-good objects.
|
||||||
// Precondition: value is not a nil pointer.
|
// Precondition: value is not a nil pointer.
|
||||||
func mustSerializeJSON(value interface{}) []byte {
|
func mustSerializeJSON(value interface{}) []byte {
|
||||||
@ -162,7 +147,7 @@ func (b *byteBuffer) UnmarshalJSON(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
decoded, err := base64URLDecode(encoded)
|
decoded, err := base64.RawURLEncoding.DecodeString(encoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -173,7 +158,7 @@ func (b *byteBuffer) UnmarshalJSON(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *byteBuffer) base64() string {
|
func (b *byteBuffer) base64() string {
|
||||||
return base64URLEncode(b.data)
|
return base64.RawURLEncoding.EncodeToString(b.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *byteBuffer) bytes() []byte {
|
func (b *byteBuffer) bytes() []byte {
|
@ -10,7 +10,7 @@ go_library(
|
|||||||
"stream.go",
|
"stream.go",
|
||||||
"tags.go",
|
"tags.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/square/go-jose/json",
|
importpath = "gopkg.in/square/go-jose.v2/json",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
95
vendor/github.com/square/go-jose/jwe.go → vendor/gopkg.in/square/go-jose.v2/jwe.go
generated
vendored
95
vendor/github.com/square/go-jose/jwe.go → vendor/gopkg.in/square/go-jose.v2/jwe.go
generated
vendored
@ -17,14 +17,14 @@
|
|||||||
package jose
|
package jose
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/square/go-jose/json"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// rawJsonWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
|
// rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
|
||||||
type rawJsonWebEncryption struct {
|
type rawJSONWebEncryption struct {
|
||||||
Protected *byteBuffer `json:"protected,omitempty"`
|
Protected *byteBuffer `json:"protected,omitempty"`
|
||||||
Unprotected *rawHeader `json:"unprotected,omitempty"`
|
Unprotected *rawHeader `json:"unprotected,omitempty"`
|
||||||
Header *rawHeader `json:"header,omitempty"`
|
Header *rawHeader `json:"header,omitempty"`
|
||||||
@ -42,13 +42,13 @@ type rawRecipientInfo struct {
|
|||||||
EncryptedKey string `json:"encrypted_key,omitempty"`
|
EncryptedKey string `json:"encrypted_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JsonWebEncryption represents an encrypted JWE object after parsing.
|
// JSONWebEncryption represents an encrypted JWE object after parsing.
|
||||||
type JsonWebEncryption struct {
|
type JSONWebEncryption struct {
|
||||||
Header JoseHeader
|
Header Header
|
||||||
protected, unprotected *rawHeader
|
protected, unprotected *rawHeader
|
||||||
recipients []recipientInfo
|
recipients []recipientInfo
|
||||||
aad, iv, ciphertext, tag []byte
|
aad, iv, ciphertext, tag []byte
|
||||||
original *rawJsonWebEncryption
|
original *rawJSONWebEncryption
|
||||||
}
|
}
|
||||||
|
|
||||||
// recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
|
// recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
|
||||||
@ -58,7 +58,7 @@ type recipientInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthData retrieves the (optional) authenticated data attached to the object.
|
// GetAuthData retrieves the (optional) authenticated data attached to the object.
|
||||||
func (obj JsonWebEncryption) GetAuthData() []byte {
|
func (obj JSONWebEncryption) GetAuthData() []byte {
|
||||||
if obj.aad != nil {
|
if obj.aad != nil {
|
||||||
out := make([]byte, len(obj.aad))
|
out := make([]byte, len(obj.aad))
|
||||||
copy(out, obj.aad)
|
copy(out, obj.aad)
|
||||||
@ -69,7 +69,7 @@ func (obj JsonWebEncryption) GetAuthData() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the merged header values
|
// Get the merged header values
|
||||||
func (obj JsonWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
|
func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
|
||||||
out := rawHeader{}
|
out := rawHeader{}
|
||||||
out.merge(obj.protected)
|
out.merge(obj.protected)
|
||||||
out.merge(obj.unprotected)
|
out.merge(obj.unprotected)
|
||||||
@ -82,26 +82,26 @@ func (obj JsonWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the additional authenticated data from a JWE object.
|
// Get the additional authenticated data from a JWE object.
|
||||||
func (obj JsonWebEncryption) computeAuthData() []byte {
|
func (obj JSONWebEncryption) computeAuthData() []byte {
|
||||||
var protected string
|
var protected string
|
||||||
|
|
||||||
if obj.original != nil {
|
if obj.original != nil {
|
||||||
protected = obj.original.Protected.base64()
|
protected = obj.original.Protected.base64()
|
||||||
} else {
|
} else {
|
||||||
protected = base64URLEncode(mustSerializeJSON((obj.protected)))
|
protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
|
||||||
}
|
}
|
||||||
|
|
||||||
output := []byte(protected)
|
output := []byte(protected)
|
||||||
if obj.aad != nil {
|
if obj.aad != nil {
|
||||||
output = append(output, '.')
|
output = append(output, '.')
|
||||||
output = append(output, []byte(base64URLEncode(obj.aad))...)
|
output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseEncrypted parses an encrypted message in compact or full serialization format.
|
// ParseEncrypted parses an encrypted message in compact or full serialization format.
|
||||||
func ParseEncrypted(input string) (*JsonWebEncryption, error) {
|
func ParseEncrypted(input string) (*JSONWebEncryption, error) {
|
||||||
input = stripWhitespace(input)
|
input = stripWhitespace(input)
|
||||||
if strings.HasPrefix(input, "{") {
|
if strings.HasPrefix(input, "{") {
|
||||||
return parseEncryptedFull(input)
|
return parseEncryptedFull(input)
|
||||||
@ -111,8 +111,8 @@ func ParseEncrypted(input string) (*JsonWebEncryption, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseEncryptedFull parses a message in compact format.
|
// parseEncryptedFull parses a message in compact format.
|
||||||
func parseEncryptedFull(input string) (*JsonWebEncryption, error) {
|
func parseEncryptedFull(input string) (*JSONWebEncryption, error) {
|
||||||
var parsed rawJsonWebEncryption
|
var parsed rawJSONWebEncryption
|
||||||
err := json.Unmarshal([]byte(input), &parsed)
|
err := json.Unmarshal([]byte(input), &parsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -122,16 +122,22 @@ func parseEncryptedFull(input string) (*JsonWebEncryption, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sanitized produces a cleaned-up JWE object from the raw JSON.
|
// sanitized produces a cleaned-up JWE object from the raw JSON.
|
||||||
func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) {
|
||||||
obj := &JsonWebEncryption{
|
obj := &JSONWebEncryption{
|
||||||
original: parsed,
|
original: parsed,
|
||||||
unprotected: parsed.Unprotected,
|
unprotected: parsed.Unprotected,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is not a nonce in the unprotected headers
|
// Check that there is not a nonce in the unprotected headers
|
||||||
if (parsed.Unprotected != nil && parsed.Unprotected.Nonce != "") ||
|
if parsed.Unprotected != nil {
|
||||||
(parsed.Header != nil && parsed.Header.Nonce != "") {
|
if nonce := parsed.Unprotected.getNonce(); nonce != "" {
|
||||||
return nil, ErrUnprotectedNonce
|
return nil, ErrUnprotectedNonce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parsed.Header != nil {
|
||||||
|
if nonce := parsed.Header.getNonce(); nonce != "" {
|
||||||
|
return nil, ErrUnprotectedNonce
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
||||||
@ -143,11 +149,16 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
|||||||
|
|
||||||
// Note: this must be called _after_ we parse the protected header,
|
// Note: this must be called _after_ we parse the protected header,
|
||||||
// otherwise fields from the protected header will not get picked up.
|
// otherwise fields from the protected header will not get picked up.
|
||||||
obj.Header = obj.mergedHeaders(nil).sanitized()
|
var err error
|
||||||
|
mergedHeaders := obj.mergedHeaders(nil)
|
||||||
|
obj.Header, err = mergedHeaders.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
if len(parsed.Recipients) == 0 {
|
if len(parsed.Recipients) == 0 {
|
||||||
obj.recipients = []recipientInfo{
|
obj.recipients = []recipientInfo{
|
||||||
recipientInfo{
|
{
|
||||||
header: parsed.Header,
|
header: parsed.Header,
|
||||||
encryptedKey: parsed.EncryptedKey.bytes(),
|
encryptedKey: parsed.EncryptedKey.bytes(),
|
||||||
},
|
},
|
||||||
@ -155,13 +166,13 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
|||||||
} else {
|
} else {
|
||||||
obj.recipients = make([]recipientInfo, len(parsed.Recipients))
|
obj.recipients = make([]recipientInfo, len(parsed.Recipients))
|
||||||
for r := range parsed.Recipients {
|
for r := range parsed.Recipients {
|
||||||
encryptedKey, err := base64URLDecode(parsed.Recipients[r].EncryptedKey)
|
encryptedKey, err := base64.RawURLEncoding.DecodeString(parsed.Recipients[r].EncryptedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is not a nonce in the unprotected header
|
// Check that there is not a nonce in the unprotected header
|
||||||
if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.Nonce != "" {
|
if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.getNonce() != "" {
|
||||||
return nil, ErrUnprotectedNonce
|
return nil, ErrUnprotectedNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +183,7 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
|||||||
|
|
||||||
for _, recipient := range obj.recipients {
|
for _, recipient := range obj.recipients {
|
||||||
headers := obj.mergedHeaders(&recipient)
|
headers := obj.mergedHeaders(&recipient)
|
||||||
if headers.Alg == "" || headers.Enc == "" {
|
if headers.getAlgorithm() == "" || headers.getEncryption() == "" {
|
||||||
return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
|
return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,38 +197,38 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseEncryptedCompact parses a message in compact format.
|
// parseEncryptedCompact parses a message in compact format.
|
||||||
func parseEncryptedCompact(input string) (*JsonWebEncryption, error) {
|
func parseEncryptedCompact(input string) (*JSONWebEncryption, error) {
|
||||||
parts := strings.Split(input, ".")
|
parts := strings.Split(input, ".")
|
||||||
if len(parts) != 5 {
|
if len(parts) != 5 {
|
||||||
return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
|
return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
|
||||||
}
|
}
|
||||||
|
|
||||||
rawProtected, err := base64URLDecode(parts[0])
|
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedKey, err := base64URLDecode(parts[1])
|
encryptedKey, err := base64.RawURLEncoding.DecodeString(parts[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iv, err := base64URLDecode(parts[2])
|
iv, err := base64.RawURLEncoding.DecodeString(parts[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ciphertext, err := base64URLDecode(parts[3])
|
ciphertext, err := base64.RawURLEncoding.DecodeString(parts[3])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tag, err := base64URLDecode(parts[4])
|
tag, err := base64.RawURLEncoding.DecodeString(parts[4])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := &rawJsonWebEncryption{
|
raw := &rawJSONWebEncryption{
|
||||||
Protected: newBuffer(rawProtected),
|
Protected: newBuffer(rawProtected),
|
||||||
EncryptedKey: newBuffer(encryptedKey),
|
EncryptedKey: newBuffer(encryptedKey),
|
||||||
Iv: newBuffer(iv),
|
Iv: newBuffer(iv),
|
||||||
@ -229,7 +240,7 @@ func parseEncryptedCompact(input string) (*JsonWebEncryption, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CompactSerialize serializes an object using the compact serialization format.
|
// CompactSerialize serializes an object using the compact serialization format.
|
||||||
func (obj JsonWebEncryption) CompactSerialize() (string, error) {
|
func (obj JSONWebEncryption) CompactSerialize() (string, error) {
|
||||||
if len(obj.recipients) != 1 || obj.unprotected != nil ||
|
if len(obj.recipients) != 1 || obj.unprotected != nil ||
|
||||||
obj.protected == nil || obj.recipients[0].header != nil {
|
obj.protected == nil || obj.recipients[0].header != nil {
|
||||||
return "", ErrNotSupported
|
return "", ErrNotSupported
|
||||||
@ -239,16 +250,16 @@ func (obj JsonWebEncryption) CompactSerialize() (string, error) {
|
|||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s.%s.%s.%s.%s",
|
"%s.%s.%s.%s.%s",
|
||||||
base64URLEncode(serializedProtected),
|
base64.RawURLEncoding.EncodeToString(serializedProtected),
|
||||||
base64URLEncode(obj.recipients[0].encryptedKey),
|
base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey),
|
||||||
base64URLEncode(obj.iv),
|
base64.RawURLEncoding.EncodeToString(obj.iv),
|
||||||
base64URLEncode(obj.ciphertext),
|
base64.RawURLEncoding.EncodeToString(obj.ciphertext),
|
||||||
base64URLEncode(obj.tag)), nil
|
base64.RawURLEncoding.EncodeToString(obj.tag)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullSerialize serializes an object using the full JSON serialization format.
|
// FullSerialize serializes an object using the full JSON serialization format.
|
||||||
func (obj JsonWebEncryption) FullSerialize() string {
|
func (obj JSONWebEncryption) FullSerialize() string {
|
||||||
raw := rawJsonWebEncryption{
|
raw := rawJSONWebEncryption{
|
||||||
Unprotected: obj.unprotected,
|
Unprotected: obj.unprotected,
|
||||||
Iv: newBuffer(obj.iv),
|
Iv: newBuffer(obj.iv),
|
||||||
Ciphertext: newBuffer(obj.ciphertext),
|
Ciphertext: newBuffer(obj.ciphertext),
|
||||||
@ -262,7 +273,7 @@ func (obj JsonWebEncryption) FullSerialize() string {
|
|||||||
for _, recipient := range obj.recipients {
|
for _, recipient := range obj.recipients {
|
||||||
info := rawRecipientInfo{
|
info := rawRecipientInfo{
|
||||||
Header: recipient.header,
|
Header: recipient.header,
|
||||||
EncryptedKey: base64URLEncode(recipient.encryptedKey),
|
EncryptedKey: base64.RawURLEncoding.EncodeToString(recipient.encryptedKey),
|
||||||
}
|
}
|
||||||
raw.Recipients = append(raw.Recipients, info)
|
raw.Recipients = append(raw.Recipients, info)
|
||||||
}
|
}
|
154
vendor/github.com/square/go-jose/jwk.go → vendor/gopkg.in/square/go-jose.v2/jwk.go
generated
vendored
154
vendor/github.com/square/go-jose/jwk.go → vendor/gopkg.in/square/go-jose.v2/jwk.go
generated
vendored
@ -29,11 +29,13 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/square/go-jose/json"
|
"golang.org/x/crypto/ed25519"
|
||||||
|
|
||||||
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rawJsonWebKey represents a public or private key in JWK format, used for parsing/serializing.
|
// rawJSONWebKey represents a public or private key in JWK format, used for parsing/serializing.
|
||||||
type rawJsonWebKey struct {
|
type rawJSONWebKey struct {
|
||||||
Use string `json:"use,omitempty"`
|
Use string `json:"use,omitempty"`
|
||||||
Kty string `json:"kty,omitempty"`
|
Kty string `json:"kty,omitempty"`
|
||||||
Kid string `json:"kid,omitempty"`
|
Kid string `json:"kid,omitempty"`
|
||||||
@ -58,8 +60,8 @@ type rawJsonWebKey struct {
|
|||||||
X5c []string `json:"x5c,omitempty"`
|
X5c []string `json:"x5c,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JsonWebKey represents a public or private key in JWK format.
|
// JSONWebKey represents a public or private key in JWK format.
|
||||||
type JsonWebKey struct {
|
type JSONWebKey struct {
|
||||||
Key interface{}
|
Key interface{}
|
||||||
Certificates []*x509.Certificate
|
Certificates []*x509.Certificate
|
||||||
KeyID string
|
KeyID string
|
||||||
@ -68,15 +70,19 @@ type JsonWebKey struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON serializes the given key to its JSON representation.
|
// MarshalJSON serializes the given key to its JSON representation.
|
||||||
func (k JsonWebKey) MarshalJSON() ([]byte, error) {
|
func (k JSONWebKey) MarshalJSON() ([]byte, error) {
|
||||||
var raw *rawJsonWebKey
|
var raw *rawJSONWebKey
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
switch key := k.Key.(type) {
|
switch key := k.Key.(type) {
|
||||||
|
case ed25519.PublicKey:
|
||||||
|
raw = fromEdPublicKey(key)
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
raw, err = fromEcPublicKey(key)
|
raw, err = fromEcPublicKey(key)
|
||||||
case *rsa.PublicKey:
|
case *rsa.PublicKey:
|
||||||
raw = fromRsaPublicKey(key)
|
raw = fromRsaPublicKey(key)
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
raw, err = fromEdPrivateKey(key)
|
||||||
case *ecdsa.PrivateKey:
|
case *ecdsa.PrivateKey:
|
||||||
raw, err = fromEcPrivateKey(key)
|
raw, err = fromEcPrivateKey(key)
|
||||||
case *rsa.PrivateKey:
|
case *rsa.PrivateKey:
|
||||||
@ -103,8 +109,8 @@ func (k JsonWebKey) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON reads a key from its JSON representation.
|
// UnmarshalJSON reads a key from its JSON representation.
|
||||||
func (k *JsonWebKey) UnmarshalJSON(data []byte) (err error) {
|
func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
|
||||||
var raw rawJsonWebKey
|
var raw rawJSONWebKey
|
||||||
err = json.Unmarshal(data, &raw)
|
err = json.Unmarshal(data, &raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -126,12 +132,22 @@ func (k *JsonWebKey) UnmarshalJSON(data []byte) (err error) {
|
|||||||
}
|
}
|
||||||
case "oct":
|
case "oct":
|
||||||
key, err = raw.symmetricKey()
|
key, err = raw.symmetricKey()
|
||||||
|
case "OKP":
|
||||||
|
if raw.Crv == "Ed25519" && raw.X != nil {
|
||||||
|
if raw.D != nil {
|
||||||
|
key, err = raw.edPrivateKey()
|
||||||
|
} else {
|
||||||
|
key, err = raw.edPublicKey()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("square/go-jose: unknown curve %s'", raw.Crv)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("square/go-jose: unknown json web key type '%s'", raw.Kty)
|
err = fmt.Errorf("square/go-jose: unknown json web key type '%s'", raw.Kty)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
*k = JsonWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use}
|
*k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use}
|
||||||
}
|
}
|
||||||
|
|
||||||
k.Certificates = make([]*x509.Certificate, len(raw.X5c))
|
k.Certificates = make([]*x509.Certificate, len(raw.X5c))
|
||||||
@ -149,17 +165,17 @@ func (k *JsonWebKey) UnmarshalJSON(data []byte) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// JsonWebKeySet represents a JWK Set object.
|
// JSONWebKeySet represents a JWK Set object.
|
||||||
type JsonWebKeySet struct {
|
type JSONWebKeySet struct {
|
||||||
Keys []JsonWebKey `json:"keys"`
|
Keys []JSONWebKey `json:"keys"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key convenience method returns keys by key ID. Specification states
|
// Key convenience method returns keys by key ID. Specification states
|
||||||
// that a JWK Set "SHOULD" use distinct key IDs, but allows for some
|
// that a JWK Set "SHOULD" use distinct key IDs, but allows for some
|
||||||
// cases where they are not distinct. Hence method returns a slice
|
// cases where they are not distinct. Hence method returns a slice
|
||||||
// of JsonWebKeys.
|
// of JSONWebKeys.
|
||||||
func (s *JsonWebKeySet) Key(kid string) []JsonWebKey {
|
func (s *JSONWebKeySet) Key(kid string) []JSONWebKey {
|
||||||
var keys []JsonWebKey
|
var keys []JSONWebKey
|
||||||
for _, key := range s.Keys {
|
for _, key := range s.Keys {
|
||||||
if key.KeyID == kid {
|
if key.KeyID == kid {
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
@ -171,6 +187,7 @@ func (s *JsonWebKeySet) Key(kid string) []JsonWebKey {
|
|||||||
|
|
||||||
const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
|
const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
|
||||||
const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`
|
const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`
|
||||||
|
const edThumbprintTemplate = `{"crv":"%s","kty":"OKP",x":"%s"}`
|
||||||
|
|
||||||
func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) {
|
func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) {
|
||||||
coordLength := curveSize(curve)
|
coordLength := curveSize(curve)
|
||||||
@ -190,12 +207,20 @@ func rsaThumbprintInput(n *big.Int, e int) (string, error) {
|
|||||||
newBuffer(n.Bytes()).base64()), nil
|
newBuffer(n.Bytes()).base64()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func edThumbprintInput(ed ed25519.PublicKey) (string, error) {
|
||||||
|
crv := "Ed25519"
|
||||||
|
return fmt.Sprintf(edThumbprintTemplate, crv,
|
||||||
|
newFixedSizeBuffer(ed, 32).base64()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Thumbprint computes the JWK Thumbprint of a key using the
|
// Thumbprint computes the JWK Thumbprint of a key using the
|
||||||
// indicated hash algorithm.
|
// indicated hash algorithm.
|
||||||
func (k *JsonWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
|
func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
|
||||||
var input string
|
var input string
|
||||||
var err error
|
var err error
|
||||||
switch key := k.Key.(type) {
|
switch key := k.Key.(type) {
|
||||||
|
case ed25519.PublicKey:
|
||||||
|
input, err = edThumbprintInput(key)
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
|
input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
|
||||||
case *ecdsa.PrivateKey:
|
case *ecdsa.PrivateKey:
|
||||||
@ -204,6 +229,8 @@ func (k *JsonWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
|
|||||||
input, err = rsaThumbprintInput(key.N, key.E)
|
input, err = rsaThumbprintInput(key.N, key.E)
|
||||||
case *rsa.PrivateKey:
|
case *rsa.PrivateKey:
|
||||||
input, err = rsaThumbprintInput(key.N, key.E)
|
input, err = rsaThumbprintInput(key.N, key.E)
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
input, err = edThumbprintInput(ed25519.PublicKey(key[0:32]))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
|
return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
|
||||||
}
|
}
|
||||||
@ -217,8 +244,18 @@ func (k *JsonWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
|
|||||||
return h.Sum(nil), nil
|
return h.Sum(nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid checks that the key contains the expected parameters
|
// IsPublic returns true if the JWK represents a public key (not symmetric, not private).
|
||||||
func (k *JsonWebKey) Valid() bool {
|
func (k *JSONWebKey) IsPublic() bool {
|
||||||
|
switch k.Key.(type) {
|
||||||
|
case *ecdsa.PublicKey, *rsa.PublicKey, *ed25519.PublicKey:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid checks that the key contains the expected parameters.
|
||||||
|
func (k *JSONWebKey) Valid() bool {
|
||||||
if k.Key == nil {
|
if k.Key == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -239,13 +276,21 @@ func (k *JsonWebKey) Valid() bool {
|
|||||||
if key.N == nil || key.E == 0 || key.D == nil || len(key.Primes) < 2 {
|
if key.N == nil || key.E == 0 || key.D == nil || len(key.Primes) < 2 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case *ed25519.PublicKey:
|
||||||
|
if len(*key) != 32 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case *ed25519.PrivateKey:
|
||||||
|
if len(*key) != 64 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (key rawJsonWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
|
func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
|
||||||
if key.N == nil || key.E == nil {
|
if key.N == nil || key.E == nil {
|
||||||
return nil, fmt.Errorf("square/go-jose: invalid RSA key, missing n/e values")
|
return nil, fmt.Errorf("square/go-jose: invalid RSA key, missing n/e values")
|
||||||
}
|
}
|
||||||
@ -256,15 +301,23 @@ func (key rawJsonWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromRsaPublicKey(pub *rsa.PublicKey) *rawJsonWebKey {
|
func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
|
||||||
return &rawJsonWebKey{
|
return &rawJSONWebKey{
|
||||||
|
Kty: "OKP",
|
||||||
|
Crv: "Ed25519",
|
||||||
|
X: newBuffer(pub),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
|
||||||
|
return &rawJSONWebKey{
|
||||||
Kty: "RSA",
|
Kty: "RSA",
|
||||||
N: newBuffer(pub.N.Bytes()),
|
N: newBuffer(pub.N.Bytes()),
|
||||||
E: newBufferFromInt(uint64(pub.E)),
|
E: newBufferFromInt(uint64(pub.E)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (key rawJsonWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
|
func (key rawJSONWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
|
||||||
var curve elliptic.Curve
|
var curve elliptic.Curve
|
||||||
switch key.Crv {
|
switch key.Crv {
|
||||||
case "P-256":
|
case "P-256":
|
||||||
@ -295,7 +348,7 @@ func (key rawJsonWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJsonWebKey, error) {
|
func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJSONWebKey, error) {
|
||||||
if pub == nil || pub.X == nil || pub.Y == nil {
|
if pub == nil || pub.X == nil || pub.Y == nil {
|
||||||
return nil, fmt.Errorf("square/go-jose: invalid EC key (nil, or X/Y missing)")
|
return nil, fmt.Errorf("square/go-jose: invalid EC key (nil, or X/Y missing)")
|
||||||
}
|
}
|
||||||
@ -314,7 +367,7 @@ func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJsonWebKey, error) {
|
|||||||
return nil, fmt.Errorf("square/go-jose: invalid EC key (X/Y too large)")
|
return nil, fmt.Errorf("square/go-jose: invalid EC key (X/Y too large)")
|
||||||
}
|
}
|
||||||
|
|
||||||
key := &rawJsonWebKey{
|
key := &rawJSONWebKey{
|
||||||
Kty: "EC",
|
Kty: "EC",
|
||||||
Crv: name,
|
Crv: name,
|
||||||
X: newFixedSizeBuffer(xBytes, size),
|
X: newFixedSizeBuffer(xBytes, size),
|
||||||
@ -324,7 +377,37 @@ func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJsonWebKey, error) {
|
|||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (key rawJsonWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
func (key rawJSONWebKey) edPrivateKey() (ed25519.PrivateKey, error) {
|
||||||
|
var missing []string
|
||||||
|
switch {
|
||||||
|
case key.D == nil:
|
||||||
|
missing = append(missing, "D")
|
||||||
|
case key.X == nil:
|
||||||
|
missing = append(missing, "X")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) > 0 {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: invalid Ed25519 private key, missing %s value(s)", strings.Join(missing, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey := make([]byte, ed25519.PrivateKeySize)
|
||||||
|
copy(privateKey[0:32], key.X.bytes())
|
||||||
|
copy(privateKey[32:], key.D.bytes())
|
||||||
|
rv := ed25519.PrivateKey(privateKey)
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key rawJSONWebKey) edPublicKey() (ed25519.PublicKey, error) {
|
||||||
|
if key.X == nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: invalid Ed key, missing x value")
|
||||||
|
}
|
||||||
|
publicKey := make([]byte, ed25519.PublicKeySize)
|
||||||
|
copy(publicKey[0:32], key.X.bytes())
|
||||||
|
rv := ed25519.PublicKey(publicKey)
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
||||||
var missing []string
|
var missing []string
|
||||||
switch {
|
switch {
|
||||||
case key.N == nil:
|
case key.N == nil:
|
||||||
@ -369,7 +452,14 @@ func (key rawJsonWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
|||||||
return rv, err
|
return rv, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromRsaPrivateKey(rsa *rsa.PrivateKey) (*rawJsonWebKey, error) {
|
func fromEdPrivateKey(ed ed25519.PrivateKey) (*rawJSONWebKey, error) {
|
||||||
|
raw := fromEdPublicKey(ed25519.PublicKey(ed[0:32]))
|
||||||
|
|
||||||
|
raw.D = newBuffer(ed[32:])
|
||||||
|
return raw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromRsaPrivateKey(rsa *rsa.PrivateKey) (*rawJSONWebKey, error) {
|
||||||
if len(rsa.Primes) != 2 {
|
if len(rsa.Primes) != 2 {
|
||||||
return nil, ErrUnsupportedKeyType
|
return nil, ErrUnsupportedKeyType
|
||||||
}
|
}
|
||||||
@ -383,7 +473,7 @@ func fromRsaPrivateKey(rsa *rsa.PrivateKey) (*rawJsonWebKey, error) {
|
|||||||
return raw, nil
|
return raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (key rawJsonWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
|
func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
|
||||||
var curve elliptic.Curve
|
var curve elliptic.Curve
|
||||||
switch key.Crv {
|
switch key.Crv {
|
||||||
case "P-256":
|
case "P-256":
|
||||||
@ -417,7 +507,7 @@ func (key rawJsonWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromEcPrivateKey(ec *ecdsa.PrivateKey) (*rawJsonWebKey, error) {
|
func fromEcPrivateKey(ec *ecdsa.PrivateKey) (*rawJSONWebKey, error) {
|
||||||
raw, err := fromEcPublicKey(&ec.PublicKey)
|
raw, err := fromEcPublicKey(&ec.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -432,14 +522,14 @@ func fromEcPrivateKey(ec *ecdsa.PrivateKey) (*rawJsonWebKey, error) {
|
|||||||
return raw, nil
|
return raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromSymmetricKey(key []byte) (*rawJsonWebKey, error) {
|
func fromSymmetricKey(key []byte) (*rawJSONWebKey, error) {
|
||||||
return &rawJsonWebKey{
|
return &rawJSONWebKey{
|
||||||
Kty: "oct",
|
Kty: "oct",
|
||||||
K: newBuffer(key),
|
K: newBuffer(key),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (key rawJsonWebKey) symmetricKey() ([]byte, error) {
|
func (key rawJSONWebKey) symmetricKey() ([]byte, error) {
|
||||||
if key.K == nil {
|
if key.K == nil {
|
||||||
return nil, fmt.Errorf("square/go-jose: invalid OCT (symmetric) key, missing k value")
|
return nil, fmt.Errorf("square/go-jose: invalid OCT (symmetric) key, missing k value")
|
||||||
}
|
}
|
88
vendor/github.com/square/go-jose/jws.go → vendor/gopkg.in/square/go-jose.v2/jws.go
generated
vendored
88
vendor/github.com/square/go-jose/jws.go → vendor/gopkg.in/square/go-jose.v2/jws.go
generated
vendored
@ -17,14 +17,16 @@
|
|||||||
package jose
|
package jose
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/square/go-jose/json"
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rawJsonWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
|
// rawJSONWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
|
||||||
type rawJsonWebSignature struct {
|
type rawJSONWebSignature struct {
|
||||||
Payload *byteBuffer `json:"payload,omitempty"`
|
Payload *byteBuffer `json:"payload,omitempty"`
|
||||||
Signatures []rawSignatureInfo `json:"signatures,omitempty"`
|
Signatures []rawSignatureInfo `json:"signatures,omitempty"`
|
||||||
Protected *byteBuffer `json:"protected,omitempty"`
|
Protected *byteBuffer `json:"protected,omitempty"`
|
||||||
@ -39,16 +41,19 @@ type rawSignatureInfo struct {
|
|||||||
Signature *byteBuffer `json:"signature,omitempty"`
|
Signature *byteBuffer `json:"signature,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JsonWebSignature represents a signed JWS object after parsing.
|
// JSONWebSignature represents a signed JWS object after parsing.
|
||||||
type JsonWebSignature struct {
|
type JSONWebSignature struct {
|
||||||
payload []byte
|
payload []byte
|
||||||
|
// Signatures attached to this object (may be more than one for multi-sig).
|
||||||
|
// Be careful about accessing these directly, prefer to use Verify() or
|
||||||
|
// VerifyMulti() to ensure that the data you're getting is verified.
|
||||||
Signatures []Signature
|
Signatures []Signature
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature represents a single signature over the JWS payload and protected header.
|
// Signature represents a single signature over the JWS payload and protected header.
|
||||||
type Signature struct {
|
type Signature struct {
|
||||||
// Header fields, such as the signature algorithm
|
// Header fields, such as the signature algorithm
|
||||||
Header JoseHeader
|
Header Header
|
||||||
|
|
||||||
// The actual signature value
|
// The actual signature value
|
||||||
Signature []byte
|
Signature []byte
|
||||||
@ -59,7 +64,7 @@ type Signature struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseSigned parses a signed message in compact or full serialization format.
|
// ParseSigned parses a signed message in compact or full serialization format.
|
||||||
func ParseSigned(input string) (*JsonWebSignature, error) {
|
func ParseSigned(input string) (*JSONWebSignature, error) {
|
||||||
input = stripWhitespace(input)
|
input = stripWhitespace(input)
|
||||||
if strings.HasPrefix(input, "{") {
|
if strings.HasPrefix(input, "{") {
|
||||||
return parseSignedFull(input)
|
return parseSignedFull(input)
|
||||||
@ -77,25 +82,25 @@ func (sig Signature) mergedHeaders() rawHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute data to be signed
|
// Compute data to be signed
|
||||||
func (obj JsonWebSignature) computeAuthData(signature *Signature) []byte {
|
func (obj JSONWebSignature) computeAuthData(signature *Signature) []byte {
|
||||||
var serializedProtected string
|
var serializedProtected string
|
||||||
|
|
||||||
if signature.original != nil && signature.original.Protected != nil {
|
if signature.original != nil && signature.original.Protected != nil {
|
||||||
serializedProtected = signature.original.Protected.base64()
|
serializedProtected = signature.original.Protected.base64()
|
||||||
} else if signature.protected != nil {
|
} else if signature.protected != nil {
|
||||||
serializedProtected = base64URLEncode(mustSerializeJSON(signature.protected))
|
serializedProtected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON(signature.protected))
|
||||||
} else {
|
} else {
|
||||||
serializedProtected = ""
|
serializedProtected = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte(fmt.Sprintf("%s.%s",
|
return []byte(fmt.Sprintf("%s.%s",
|
||||||
serializedProtected,
|
serializedProtected,
|
||||||
base64URLEncode(obj.payload)))
|
base64.RawURLEncoding.EncodeToString(obj.payload)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSignedFull parses a message in full format.
|
// parseSignedFull parses a message in full format.
|
||||||
func parseSignedFull(input string) (*JsonWebSignature, error) {
|
func parseSignedFull(input string) (*JSONWebSignature, error) {
|
||||||
var parsed rawJsonWebSignature
|
var parsed rawJSONWebSignature
|
||||||
err := json.Unmarshal([]byte(input), &parsed)
|
err := json.Unmarshal([]byte(input), &parsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -105,12 +110,12 @@ func parseSignedFull(input string) (*JsonWebSignature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sanitized produces a cleaned-up JWS object from the raw JSON.
|
// sanitized produces a cleaned-up JWS object from the raw JSON.
|
||||||
func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) {
|
||||||
if parsed.Payload == nil {
|
if parsed.Payload == nil {
|
||||||
return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
|
return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
|
||||||
}
|
}
|
||||||
|
|
||||||
obj := &JsonWebSignature{
|
obj := &JSONWebSignature{
|
||||||
payload: parsed.Payload.bytes(),
|
payload: parsed.Payload.bytes(),
|
||||||
Signatures: make([]Signature, len(parsed.Signatures)),
|
Signatures: make([]Signature, len(parsed.Signatures)),
|
||||||
}
|
}
|
||||||
@ -126,7 +131,8 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsed.Header != nil && parsed.Header.Nonce != "" {
|
// Check that there is not a nonce in the unprotected header
|
||||||
|
if parsed.Header != nil && parsed.Header.getNonce() != "" {
|
||||||
return nil, ErrUnprotectedNonce
|
return nil, ErrUnprotectedNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +153,18 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
|||||||
Signature: parsed.Signature,
|
Signature: parsed.Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
signature.Header = signature.mergedHeaders().sanitized()
|
var err error
|
||||||
|
signature.Header, err = signature.mergedHeaders().sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
|
||||||
|
jwk := signature.Header.JSONWebKey
|
||||||
|
if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
|
||||||
|
return nil, errors.New("square/go-jose: invalid embedded jwk, must be public key")
|
||||||
|
}
|
||||||
|
|
||||||
obj.Signatures = append(obj.Signatures, signature)
|
obj.Signatures = append(obj.Signatures, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,46 +178,57 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is not a nonce in the unprotected header
|
// Check that there is not a nonce in the unprotected header
|
||||||
if sig.Header != nil && sig.Header.Nonce != "" {
|
if sig.Header != nil && sig.Header.getNonce() != "" {
|
||||||
return nil, ErrUnprotectedNonce
|
return nil, ErrUnprotectedNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
obj.Signatures[i].Signature = sig.Signature.bytes()
|
obj.Signatures[i].Signature = sig.Signature.bytes()
|
||||||
|
|
||||||
|
// As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
|
||||||
|
jwk := obj.Signatures[i].Header.JSONWebKey
|
||||||
|
if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
|
||||||
|
return nil, errors.New("square/go-jose: invalid embedded jwk, must be public key")
|
||||||
|
}
|
||||||
|
|
||||||
// Copy value of sig
|
// Copy value of sig
|
||||||
original := sig
|
original := sig
|
||||||
|
|
||||||
obj.Signatures[i].header = sig.Header
|
obj.Signatures[i].header = sig.Header
|
||||||
obj.Signatures[i].original = &original
|
obj.Signatures[i].original = &original
|
||||||
obj.Signatures[i].Header = obj.Signatures[i].mergedHeaders().sanitized()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSignedCompact parses a message in compact format.
|
// parseSignedCompact parses a message in compact format.
|
||||||
func parseSignedCompact(input string) (*JsonWebSignature, error) {
|
func parseSignedCompact(input string) (*JSONWebSignature, error) {
|
||||||
parts := strings.Split(input, ".")
|
parts := strings.Split(input, ".")
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
|
return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
|
||||||
}
|
}
|
||||||
|
|
||||||
rawProtected, err := base64URLDecode(parts[0])
|
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
payload, err := base64URLDecode(parts[1])
|
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
signature, err := base64URLDecode(parts[2])
|
signature, err := base64.RawURLEncoding.DecodeString(parts[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := &rawJsonWebSignature{
|
raw := &rawJSONWebSignature{
|
||||||
Payload: newBuffer(payload),
|
Payload: newBuffer(payload),
|
||||||
Protected: newBuffer(rawProtected),
|
Protected: newBuffer(rawProtected),
|
||||||
Signature: newBuffer(signature),
|
Signature: newBuffer(signature),
|
||||||
@ -209,7 +237,7 @@ func parseSignedCompact(input string) (*JsonWebSignature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CompactSerialize serializes an object using the compact serialization format.
|
// CompactSerialize serializes an object using the compact serialization format.
|
||||||
func (obj JsonWebSignature) CompactSerialize() (string, error) {
|
func (obj JSONWebSignature) CompactSerialize() (string, error) {
|
||||||
if len(obj.Signatures) != 1 || obj.Signatures[0].header != nil || obj.Signatures[0].protected == nil {
|
if len(obj.Signatures) != 1 || obj.Signatures[0].header != nil || obj.Signatures[0].protected == nil {
|
||||||
return "", ErrNotSupported
|
return "", ErrNotSupported
|
||||||
}
|
}
|
||||||
@ -218,14 +246,14 @@ func (obj JsonWebSignature) CompactSerialize() (string, error) {
|
|||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s.%s.%s",
|
"%s.%s.%s",
|
||||||
base64URLEncode(serializedProtected),
|
base64.RawURLEncoding.EncodeToString(serializedProtected),
|
||||||
base64URLEncode(obj.payload),
|
base64.RawURLEncoding.EncodeToString(obj.payload),
|
||||||
base64URLEncode(obj.Signatures[0].Signature)), nil
|
base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullSerialize serializes an object using the full JSON serialization format.
|
// FullSerialize serializes an object using the full JSON serialization format.
|
||||||
func (obj JsonWebSignature) FullSerialize() string {
|
func (obj JSONWebSignature) FullSerialize() string {
|
||||||
raw := rawJsonWebSignature{
|
raw := rawJSONWebSignature{
|
||||||
Payload: newBuffer(obj.payload),
|
Payload: newBuffer(obj.payload),
|
||||||
}
|
}
|
||||||
|
|
417
vendor/gopkg.in/square/go-jose.v2/shared.go
generated
vendored
Normal file
417
vendor/gopkg.in/square/go-jose.v2/shared.go
generated
vendored
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2014 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 jose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/elliptic"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KeyAlgorithm represents a key management algorithm.
|
||||||
|
type KeyAlgorithm string
|
||||||
|
|
||||||
|
// SignatureAlgorithm represents a signature (or MAC) algorithm.
|
||||||
|
type SignatureAlgorithm string
|
||||||
|
|
||||||
|
// ContentEncryption represents a content encryption algorithm.
|
||||||
|
type ContentEncryption string
|
||||||
|
|
||||||
|
// CompressionAlgorithm represents an algorithm used for plaintext compression.
|
||||||
|
type CompressionAlgorithm string
|
||||||
|
|
||||||
|
// ContentType represents type of the contained data.
|
||||||
|
type ContentType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrCryptoFailure represents an error in cryptographic primitive. This
|
||||||
|
// occurs when, for example, a message had an invalid authentication tag or
|
||||||
|
// could not be decrypted.
|
||||||
|
ErrCryptoFailure = errors.New("square/go-jose: error in cryptographic primitive")
|
||||||
|
|
||||||
|
// ErrUnsupportedAlgorithm indicates that a selected algorithm is not
|
||||||
|
// supported. This occurs when trying to instantiate an encrypter for an
|
||||||
|
// algorithm that is not yet implemented.
|
||||||
|
ErrUnsupportedAlgorithm = errors.New("square/go-jose: unknown/unsupported algorithm")
|
||||||
|
|
||||||
|
// ErrUnsupportedKeyType indicates that the given key type/format is not
|
||||||
|
// supported. This occurs when trying to instantiate an encrypter and passing
|
||||||
|
// it a key of an unrecognized type or with unsupported parameters, such as
|
||||||
|
// an RSA private key with more than two primes.
|
||||||
|
ErrUnsupportedKeyType = errors.New("square/go-jose: unsupported key type/format")
|
||||||
|
|
||||||
|
// ErrNotSupported serialization of object is not supported. This occurs when
|
||||||
|
// trying to compact-serialize an object which can't be represented in
|
||||||
|
// compact form.
|
||||||
|
ErrNotSupported = errors.New("square/go-jose: compact serialization not supported for object")
|
||||||
|
|
||||||
|
// ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a
|
||||||
|
// nonce header parameter was included in an unprotected header object.
|
||||||
|
ErrUnprotectedNonce = errors.New("square/go-jose: Nonce parameter included in unprotected header")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key management algorithms
|
||||||
|
const (
|
||||||
|
ED25519 = KeyAlgorithm("ED25519")
|
||||||
|
RSA1_5 = KeyAlgorithm("RSA1_5") // RSA-PKCS1v1.5
|
||||||
|
RSA_OAEP = KeyAlgorithm("RSA-OAEP") // RSA-OAEP-SHA1
|
||||||
|
RSA_OAEP_256 = KeyAlgorithm("RSA-OAEP-256") // RSA-OAEP-SHA256
|
||||||
|
A128KW = KeyAlgorithm("A128KW") // AES key wrap (128)
|
||||||
|
A192KW = KeyAlgorithm("A192KW") // AES key wrap (192)
|
||||||
|
A256KW = KeyAlgorithm("A256KW") // AES key wrap (256)
|
||||||
|
DIRECT = KeyAlgorithm("dir") // Direct encryption
|
||||||
|
ECDH_ES = KeyAlgorithm("ECDH-ES") // ECDH-ES
|
||||||
|
ECDH_ES_A128KW = KeyAlgorithm("ECDH-ES+A128KW") // ECDH-ES + AES key wrap (128)
|
||||||
|
ECDH_ES_A192KW = KeyAlgorithm("ECDH-ES+A192KW") // ECDH-ES + AES key wrap (192)
|
||||||
|
ECDH_ES_A256KW = KeyAlgorithm("ECDH-ES+A256KW") // ECDH-ES + AES key wrap (256)
|
||||||
|
A128GCMKW = KeyAlgorithm("A128GCMKW") // AES-GCM key wrap (128)
|
||||||
|
A192GCMKW = KeyAlgorithm("A192GCMKW") // AES-GCM key wrap (192)
|
||||||
|
A256GCMKW = KeyAlgorithm("A256GCMKW") // AES-GCM key wrap (256)
|
||||||
|
PBES2_HS256_A128KW = KeyAlgorithm("PBES2-HS256+A128KW") // PBES2 + HMAC-SHA256 + AES key wrap (128)
|
||||||
|
PBES2_HS384_A192KW = KeyAlgorithm("PBES2-HS384+A192KW") // PBES2 + HMAC-SHA384 + AES key wrap (192)
|
||||||
|
PBES2_HS512_A256KW = KeyAlgorithm("PBES2-HS512+A256KW") // PBES2 + HMAC-SHA512 + AES key wrap (256)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Signature algorithms
|
||||||
|
const (
|
||||||
|
EdDSA = SignatureAlgorithm("EdDSA")
|
||||||
|
HS256 = SignatureAlgorithm("HS256") // HMAC using SHA-256
|
||||||
|
HS384 = SignatureAlgorithm("HS384") // HMAC using SHA-384
|
||||||
|
HS512 = SignatureAlgorithm("HS512") // HMAC using SHA-512
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
// Content encryption algorithms
|
||||||
|
const (
|
||||||
|
A128CBC_HS256 = ContentEncryption("A128CBC-HS256") // AES-CBC + HMAC-SHA256 (128)
|
||||||
|
A192CBC_HS384 = ContentEncryption("A192CBC-HS384") // AES-CBC + HMAC-SHA384 (192)
|
||||||
|
A256CBC_HS512 = ContentEncryption("A256CBC-HS512") // AES-CBC + HMAC-SHA512 (256)
|
||||||
|
A128GCM = ContentEncryption("A128GCM") // AES-GCM (128)
|
||||||
|
A192GCM = ContentEncryption("A192GCM") // AES-GCM (192)
|
||||||
|
A256GCM = ContentEncryption("A256GCM") // AES-GCM (256)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compression algorithms
|
||||||
|
const (
|
||||||
|
NONE = CompressionAlgorithm("") // No compression
|
||||||
|
DEFLATE = CompressionAlgorithm("DEF") // DEFLATE (RFC 1951)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A key in the protected header of a JWS object. Use of the Header...
|
||||||
|
// constants is preferred to enhance type safety.
|
||||||
|
type HeaderKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
HeaderType HeaderKey = "typ" // string
|
||||||
|
HeaderContentType = "cty" // string
|
||||||
|
|
||||||
|
// These are set by go-jose and shouldn't need to be set by consumers of the
|
||||||
|
// library.
|
||||||
|
headerAlgorithm = "alg" // string
|
||||||
|
headerEncryption = "enc" // ContentEncryption
|
||||||
|
headerCompression = "zip" // CompressionAlgorithm
|
||||||
|
headerCritical = "crit" // []string
|
||||||
|
|
||||||
|
headerAPU = "apu" // *byteBuffer
|
||||||
|
headerAPV = "apv" // *byteBuffer
|
||||||
|
headerEPK = "epk" // *JSONWebKey
|
||||||
|
headerIV = "iv" // *byteBuffer
|
||||||
|
headerTag = "tag" // *byteBuffer
|
||||||
|
|
||||||
|
headerJWK = "jwk" // *JSONWebKey
|
||||||
|
headerKeyID = "kid" // string
|
||||||
|
headerNonce = "nonce" // string
|
||||||
|
)
|
||||||
|
|
||||||
|
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
|
||||||
|
//
|
||||||
|
// The decoding of the constituent items is deferred because we want to marshal
|
||||||
|
// some members into particular structs rather than generic maps, but at the
|
||||||
|
// same time we need to receive any extra fields unhandled by this library to
|
||||||
|
// pass through to consuming code in case it wants to examine them.
|
||||||
|
type rawHeader map[HeaderKey]*json.RawMessage
|
||||||
|
|
||||||
|
// Header represents the read-only JOSE header for JWE/JWS objects.
|
||||||
|
type Header struct {
|
||||||
|
KeyID string
|
||||||
|
JSONWebKey *JSONWebKey
|
||||||
|
Algorithm string
|
||||||
|
Nonce string
|
||||||
|
|
||||||
|
// Any headers not recognised above get unmarshaled from JSON in a generic
|
||||||
|
// manner and placed in this map.
|
||||||
|
ExtraHeaders map[HeaderKey]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parsed rawHeader) set(k HeaderKey, v interface{}) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed[k] = makeRawMessage(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getString gets a string from the raw JSON, defaulting to "".
|
||||||
|
func (parsed rawHeader) getString(k HeaderKey) string {
|
||||||
|
v, ok := parsed[k]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
err := json.Unmarshal(*v, &s)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// getByteBuffer gets a byte buffer from the raw JSON. Returns (nil, nil) if
|
||||||
|
// not specified.
|
||||||
|
func (parsed rawHeader) getByteBuffer(k HeaderKey) (*byteBuffer, error) {
|
||||||
|
v := parsed[k]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var bb *byteBuffer
|
||||||
|
err := json.Unmarshal(*v, &bb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAlgorithm extracts parsed "alg" from the raw JSON as a KeyAlgorithm.
|
||||||
|
func (parsed rawHeader) getAlgorithm() KeyAlgorithm {
|
||||||
|
return KeyAlgorithm(parsed.getString(headerAlgorithm))
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSignatureAlgorithm extracts parsed "alg" from the raw JSON as a SignatureAlgorithm.
|
||||||
|
func (parsed rawHeader) getSignatureAlgorithm() SignatureAlgorithm {
|
||||||
|
return SignatureAlgorithm(parsed.getString(headerAlgorithm))
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEncryption extracts parsed "enc" from the raw JSON.
|
||||||
|
func (parsed rawHeader) getEncryption() ContentEncryption {
|
||||||
|
return ContentEncryption(parsed.getString(headerEncryption))
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCompression extracts parsed "zip" from the raw JSON.
|
||||||
|
func (parsed rawHeader) getCompression() CompressionAlgorithm {
|
||||||
|
return CompressionAlgorithm(parsed.getString(headerCompression))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parsed rawHeader) getNonce() string {
|
||||||
|
return parsed.getString(headerNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEPK extracts parsed "epk" from the raw JSON.
|
||||||
|
func (parsed rawHeader) getEPK() (*JSONWebKey, error) {
|
||||||
|
v := parsed[headerEPK]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var epk *JSONWebKey
|
||||||
|
err := json.Unmarshal(*v, &epk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return epk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAPU extracts parsed "apu" from the raw JSON.
|
||||||
|
func (parsed rawHeader) getAPU() (*byteBuffer, error) {
|
||||||
|
return parsed.getByteBuffer(headerAPU)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAPV extracts parsed "apv" from the raw JSON.
|
||||||
|
func (parsed rawHeader) getAPV() (*byteBuffer, error) {
|
||||||
|
return parsed.getByteBuffer(headerAPV)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getIV extracts parsed "iv" frpom the raw JSON.
|
||||||
|
func (parsed rawHeader) getIV() (*byteBuffer, error) {
|
||||||
|
return parsed.getByteBuffer(headerIV)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTag extracts parsed "tag" frpom the raw JSON.
|
||||||
|
func (parsed rawHeader) getTag() (*byteBuffer, error) {
|
||||||
|
return parsed.getByteBuffer(headerTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getJWK extracts parsed "jwk" from the raw JSON.
|
||||||
|
func (parsed rawHeader) getJWK() (*JSONWebKey, error) {
|
||||||
|
v := parsed[headerJWK]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var jwk *JSONWebKey
|
||||||
|
err := json.Unmarshal(*v, &jwk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return jwk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCritical extracts parsed "crit" from the raw JSON. If omitted, it
|
||||||
|
// returns an empty slice.
|
||||||
|
func (parsed rawHeader) getCritical() ([]string, error) {
|
||||||
|
v := parsed[headerCritical]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var q []string
|
||||||
|
err := json.Unmarshal(*v, &q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitized produces a cleaned-up header object from the raw JSON.
|
||||||
|
func (parsed rawHeader) sanitized() (h Header, err error) {
|
||||||
|
for k, v := range parsed {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case headerJWK:
|
||||||
|
var jwk *JSONWebKey
|
||||||
|
err = json.Unmarshal(*v, &jwk)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal JWK: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.JSONWebKey = jwk
|
||||||
|
case headerKeyID:
|
||||||
|
var s string
|
||||||
|
err = json.Unmarshal(*v, &s)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal key ID: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.KeyID = s
|
||||||
|
case headerAlgorithm:
|
||||||
|
var s string
|
||||||
|
err = json.Unmarshal(*v, &s)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal algorithm: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.Algorithm = s
|
||||||
|
case headerNonce:
|
||||||
|
var s string
|
||||||
|
err = json.Unmarshal(*v, &s)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal nonce: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.Nonce = s
|
||||||
|
default:
|
||||||
|
if h.ExtraHeaders == nil {
|
||||||
|
h.ExtraHeaders = map[HeaderKey]interface{}{}
|
||||||
|
}
|
||||||
|
var v2 interface{}
|
||||||
|
err = json.Unmarshal(*v, &v2)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal value: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.ExtraHeaders[k] = v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dst rawHeader) isSet(k HeaderKey) bool {
|
||||||
|
dvr := dst[k]
|
||||||
|
if dvr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var dv interface{}
|
||||||
|
err := json.Unmarshal(*dvr, &dv)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if dvStr, ok := dv.(string); ok {
|
||||||
|
return dvStr != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge headers from src into dst, giving precedence to headers from l.
|
||||||
|
func (dst rawHeader) merge(src *rawHeader) {
|
||||||
|
if src == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range *src {
|
||||||
|
if dst.isSet(k) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get JOSE name of curve
|
||||||
|
func curveName(crv elliptic.Curve) (string, error) {
|
||||||
|
switch crv {
|
||||||
|
case elliptic.P256():
|
||||||
|
return "P-256", nil
|
||||||
|
case elliptic.P384():
|
||||||
|
return "P-384", nil
|
||||||
|
case elliptic.P521():
|
||||||
|
return "P-521", nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("square/go-jose: unsupported/unknown elliptic curve")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get size of curve in bytes
|
||||||
|
func curveSize(crv elliptic.Curve) int {
|
||||||
|
bits := crv.Params().BitSize
|
||||||
|
|
||||||
|
div := bits / 8
|
||||||
|
mod := bits % 8
|
||||||
|
|
||||||
|
if mod == 0 {
|
||||||
|
return div
|
||||||
|
}
|
||||||
|
|
||||||
|
return div + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRawMessage(b []byte) *json.RawMessage {
|
||||||
|
rm := json.RawMessage(b)
|
||||||
|
return &rm
|
||||||
|
}
|
343
vendor/gopkg.in/square/go-jose.v2/signing.go
generated
vendored
Normal file
343
vendor/gopkg.in/square/go-jose.v2/signing.go
generated
vendored
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright 2014 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 jose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
|
|
||||||
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NonceSource represents a source of random nonces to go into JWS objects
|
||||||
|
type NonceSource interface {
|
||||||
|
Nonce() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signer represents a signer which takes a payload and produces a signed JWS object.
|
||||||
|
type Signer interface {
|
||||||
|
Sign(payload []byte) (*JSONWebSignature, error)
|
||||||
|
Options() SignerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// SigningKey represents an algorithm/key used to sign a message.
|
||||||
|
type SigningKey struct {
|
||||||
|
Algorithm SignatureAlgorithm
|
||||||
|
Key interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignerOptions represents options that can be set when creating signers.
|
||||||
|
type SignerOptions struct {
|
||||||
|
NonceSource NonceSource
|
||||||
|
EmbedJWK bool
|
||||||
|
|
||||||
|
// Optional map of additional keys to be inserted into the protected header
|
||||||
|
// of a JWS object. Some specifications which make use of JWS like to insert
|
||||||
|
// additional values here. All values must be JSON-serializable.
|
||||||
|
ExtraHeaders map[HeaderKey]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it
|
||||||
|
// if necessary. It returns itself and so can be used in a fluent style.
|
||||||
|
func (so *SignerOptions) WithHeader(k HeaderKey, v interface{}) *SignerOptions {
|
||||||
|
if so.ExtraHeaders == nil {
|
||||||
|
so.ExtraHeaders = map[HeaderKey]interface{}{}
|
||||||
|
}
|
||||||
|
so.ExtraHeaders[k] = v
|
||||||
|
return so
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContentType adds a content type ("cty") header and returns the updated
|
||||||
|
// SignerOptions.
|
||||||
|
func (so *SignerOptions) WithContentType(contentType ContentType) *SignerOptions {
|
||||||
|
return so.WithHeader(HeaderContentType, contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithType adds a type ("typ") header and returns the updated SignerOptions.
|
||||||
|
func (so *SignerOptions) WithType(typ ContentType) *SignerOptions {
|
||||||
|
return so.WithHeader(HeaderType, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
type payloadSigner interface {
|
||||||
|
signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type payloadVerifier interface {
|
||||||
|
verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type genericSigner struct {
|
||||||
|
recipients []recipientSigInfo
|
||||||
|
nonceSource NonceSource
|
||||||
|
embedJWK bool
|
||||||
|
extraHeaders map[HeaderKey]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type recipientSigInfo struct {
|
||||||
|
sigAlg SignatureAlgorithm
|
||||||
|
publicKey *JSONWebKey
|
||||||
|
signer payloadSigner
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSigner creates an appropriate signer based on the key type
|
||||||
|
func NewSigner(sig SigningKey, opts *SignerOptions) (Signer, error) {
|
||||||
|
return NewMultiSigner([]SigningKey{sig}, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMultiSigner creates a signer for multiple recipients
|
||||||
|
func NewMultiSigner(sigs []SigningKey, opts *SignerOptions) (Signer, error) {
|
||||||
|
signer := &genericSigner{recipients: []recipientSigInfo{}}
|
||||||
|
|
||||||
|
if opts != nil {
|
||||||
|
signer.nonceSource = opts.NonceSource
|
||||||
|
signer.embedJWK = opts.EmbedJWK
|
||||||
|
signer.extraHeaders = opts.ExtraHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sig := range sigs {
|
||||||
|
err := signer.addRecipient(sig.Algorithm, sig.Key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newVerifier creates a verifier based on the key type
|
||||||
|
func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
|
||||||
|
switch verificationKey := verificationKey.(type) {
|
||||||
|
case ed25519.PublicKey:
|
||||||
|
return &edEncrypterVerifier{
|
||||||
|
publicKey: verificationKey,
|
||||||
|
}, nil
|
||||||
|
case *rsa.PublicKey:
|
||||||
|
return &rsaEncrypterVerifier{
|
||||||
|
publicKey: verificationKey,
|
||||||
|
}, nil
|
||||||
|
case *ecdsa.PublicKey:
|
||||||
|
return &ecEncrypterVerifier{
|
||||||
|
publicKey: verificationKey,
|
||||||
|
}, nil
|
||||||
|
case []byte:
|
||||||
|
return &symmetricMac{
|
||||||
|
key: verificationKey,
|
||||||
|
}, nil
|
||||||
|
case JSONWebKey:
|
||||||
|
return newVerifier(verificationKey.Key)
|
||||||
|
case *JSONWebKey:
|
||||||
|
return newVerifier(verificationKey.Key)
|
||||||
|
default:
|
||||||
|
return nil, ErrUnsupportedKeyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error {
|
||||||
|
recipient, err := makeJWSRecipient(alg, signingKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.recipients = append(ctx.recipients, recipient)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipientSigInfo, error) {
|
||||||
|
switch signingKey := signingKey.(type) {
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
return newEd25519Signer(alg, signingKey)
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
return newRSASigner(alg, signingKey)
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
return newECDSASigner(alg, signingKey)
|
||||||
|
case []byte:
|
||||||
|
return newSymmetricSigner(alg, signingKey)
|
||||||
|
case JSONWebKey:
|
||||||
|
return newJWKSigner(alg, signingKey)
|
||||||
|
case *JSONWebKey:
|
||||||
|
return newJWKSigner(alg, *signingKey)
|
||||||
|
default:
|
||||||
|
return recipientSigInfo{}, ErrUnsupportedKeyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) {
|
||||||
|
recipient, err := makeJWSRecipient(alg, signingKey.Key)
|
||||||
|
if err != nil {
|
||||||
|
return recipientSigInfo{}, err
|
||||||
|
}
|
||||||
|
if recipient.publicKey != nil {
|
||||||
|
// recipient.publicKey is a JWK synthesized for embedding when recipientSigInfo
|
||||||
|
// was created for the inner key (such as a RSA or ECDSA public key). It contains
|
||||||
|
// the pub key for embedding, but doesn't have extra params like key id.
|
||||||
|
publicKey := signingKey
|
||||||
|
publicKey.Key = recipient.publicKey.Key
|
||||||
|
recipient.publicKey = &publicKey
|
||||||
|
|
||||||
|
// This should be impossible, but let's check anyway.
|
||||||
|
if !recipient.publicKey.IsPublic() {
|
||||||
|
return recipientSigInfo{}, errors.New("square/go-jose: public key was unexpectedly not public")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recipient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
|
||||||
|
obj := &JSONWebSignature{}
|
||||||
|
obj.payload = payload
|
||||||
|
obj.Signatures = make([]Signature, len(ctx.recipients))
|
||||||
|
|
||||||
|
for i, recipient := range ctx.recipients {
|
||||||
|
protected := map[HeaderKey]interface{}{
|
||||||
|
headerAlgorithm: string(recipient.sigAlg),
|
||||||
|
}
|
||||||
|
|
||||||
|
if recipient.publicKey != nil {
|
||||||
|
// We want to embed the JWK or set the kid header, but not both. Having a protected
|
||||||
|
// header that contains an embedded JWK while also simultaneously containing the kid
|
||||||
|
// header is confusing, and at least in ACME the two are considered to be mutually
|
||||||
|
// exclusive. The fact that both can exist at the same time is a somewhat unfortunate
|
||||||
|
// result of the JOSE spec. We've decided that this library will only include one or
|
||||||
|
// the other to avoid this confusion.
|
||||||
|
//
|
||||||
|
// See https://github.com/square/go-jose/issues/157 for more context.
|
||||||
|
if ctx.embedJWK {
|
||||||
|
protected[headerJWK] = recipient.publicKey
|
||||||
|
} else {
|
||||||
|
protected[headerKeyID] = recipient.publicKey.KeyID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.nonceSource != nil {
|
||||||
|
nonce, err := ctx.nonceSource.Nonce()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: Error generating nonce: %v", err)
|
||||||
|
}
|
||||||
|
protected[headerNonce] = nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range ctx.extraHeaders {
|
||||||
|
protected[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedProtected := mustSerializeJSON(protected)
|
||||||
|
|
||||||
|
input := []byte(fmt.Sprintf("%s.%s",
|
||||||
|
base64.RawURLEncoding.EncodeToString(serializedProtected),
|
||||||
|
base64.RawURLEncoding.EncodeToString(payload)))
|
||||||
|
|
||||||
|
signatureInfo, err := recipient.signer.signPayload(input, recipient.sigAlg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureInfo.protected = &rawHeader{}
|
||||||
|
for k, v := range protected {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: Error marshalling item %#v: %v", k, err)
|
||||||
|
}
|
||||||
|
(*signatureInfo.protected)[k] = makeRawMessage(b)
|
||||||
|
}
|
||||||
|
obj.Signatures[i] = signatureInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *genericSigner) Options() SignerOptions {
|
||||||
|
return SignerOptions{
|
||||||
|
NonceSource: ctx.nonceSource,
|
||||||
|
EmbedJWK: ctx.embedJWK,
|
||||||
|
ExtraHeaders: ctx.extraHeaders,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify validates the signature on the object and returns the payload.
|
||||||
|
// This function does not support multi-signature, if you desire multi-sig
|
||||||
|
// verification use VerifyMulti instead.
|
||||||
|
//
|
||||||
|
// Be careful when verifying signatures based on embedded JWKs inside the
|
||||||
|
// payload header. You cannot assume that the key received in a payload is
|
||||||
|
// trusted.
|
||||||
|
func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
|
||||||
|
verifier, err := newVerifier(verificationKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(obj.Signatures) > 1 {
|
||||||
|
return nil, errors.New("square/go-jose: too many signatures in payload; expecting only one")
|
||||||
|
}
|
||||||
|
|
||||||
|
signature := obj.Signatures[0]
|
||||||
|
headers := signature.mergedHeaders()
|
||||||
|
critical, err := headers.getCritical()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(critical) > 0 {
|
||||||
|
// Unsupported crit header
|
||||||
|
return nil, ErrCryptoFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
input := obj.computeAuthData(&signature)
|
||||||
|
alg := headers.getSignatureAlgorithm()
|
||||||
|
err = verifier.verifyPayload(input, signature.Signature, alg)
|
||||||
|
if err == nil {
|
||||||
|
return obj.payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrCryptoFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyMulti validates (one of the multiple) signatures on the object and
|
||||||
|
// returns the index of the signature that was verified, along with the signature
|
||||||
|
// object and the payload. We return the signature and index to guarantee that
|
||||||
|
// callers are getting the verified value.
|
||||||
|
func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) {
|
||||||
|
verifier, err := newVerifier(verificationKey)
|
||||||
|
if err != nil {
|
||||||
|
return -1, Signature{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, signature := range obj.Signatures {
|
||||||
|
headers := signature.mergedHeaders()
|
||||||
|
critical, err := headers.getCritical()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(critical) > 0 {
|
||||||
|
// Unsupported crit header
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
input := obj.computeAuthData(&signature)
|
||||||
|
alg := headers.getSignatureAlgorithm()
|
||||||
|
err = verifier.verifyPayload(input, signature.Signature, alg)
|
||||||
|
if err == nil {
|
||||||
|
return i, signature, obj.payload, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1, Signature{}, nil, ErrCryptoFailure
|
||||||
|
}
|
@ -25,10 +25,11 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/square/go-jose/cipher"
|
"gopkg.in/square/go-jose.v2/cipher"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Random reader (stubbed out in tests)
|
// Random reader (stubbed out in tests)
|
||||||
@ -229,11 +230,12 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
|
|||||||
return recipientInfo{}, err
|
return recipientInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header := &rawHeader{}
|
||||||
|
header.set(headerIV, newBuffer(parts.iv))
|
||||||
|
header.set(headerTag, newBuffer(parts.tag))
|
||||||
|
|
||||||
return recipientInfo{
|
return recipientInfo{
|
||||||
header: &rawHeader{
|
header: header,
|
||||||
Iv: newBuffer(parts.iv),
|
|
||||||
Tag: newBuffer(parts.tag),
|
|
||||||
},
|
|
||||||
encryptedKey: parts.ciphertext,
|
encryptedKey: parts.ciphertext,
|
||||||
}, nil
|
}, nil
|
||||||
case A128KW, A192KW, A256KW:
|
case A128KW, A192KW, A256KW:
|
||||||
@ -258,7 +260,7 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
|
|||||||
|
|
||||||
// Decrypt the content encryption key.
|
// Decrypt the content encryption key.
|
||||||
func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
|
func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
|
||||||
switch KeyAlgorithm(headers.Alg) {
|
switch headers.getAlgorithm() {
|
||||||
case DIRECT:
|
case DIRECT:
|
||||||
cek := make([]byte, len(ctx.key))
|
cek := make([]byte, len(ctx.key))
|
||||||
copy(cek, ctx.key)
|
copy(cek, ctx.key)
|
||||||
@ -266,10 +268,19 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
|
|||||||
case A128GCMKW, A192GCMKW, A256GCMKW:
|
case A128GCMKW, A192GCMKW, A256GCMKW:
|
||||||
aead := newAESGCM(len(ctx.key))
|
aead := newAESGCM(len(ctx.key))
|
||||||
|
|
||||||
|
iv, err := headers.getIV()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: invalid IV: %v", err)
|
||||||
|
}
|
||||||
|
tag, err := headers.getTag()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("square/go-jose: invalid tag: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
parts := &aeadParts{
|
parts := &aeadParts{
|
||||||
iv: headers.Iv.bytes(),
|
iv: iv.bytes(),
|
||||||
ciphertext: recipient.encryptedKey,
|
ciphertext: recipient.encryptedKey,
|
||||||
tag: headers.Tag.bytes(),
|
tag: tag.bytes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
cek, err := aead.decrypt(ctx.key, []byte{}, parts)
|
cek, err := aead.decrypt(ctx.key, []byte{}, parts)
|
Loading…
Reference in New Issue
Block a user