mirror of https://github.com/k3s-io/k3s
godeps: bump gopkg.in/square/go-jose.v2
pickup https://github.com/square/go-jose/pull/179pull/8/head
parent
169bfbc7f5
commit
9ea39419eb
|
@ -3669,22 +3669,22 @@
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2",
|
"ImportPath": "gopkg.in/square/go-jose.v2",
|
||||||
"Comment": "v2.1.3",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
||||||
"Comment": "v2.1.3",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
||||||
"Comment": "v2.1.3",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/jwt",
|
"ImportPath": "gopkg.in/square/go-jose.v2/jwt",
|
||||||
"Comment": "v2.1.3",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/warnings.v0",
|
"ImportPath": "gopkg.in/warnings.v0",
|
||||||
|
|
|
@ -840,15 +840,15 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2",
|
"ImportPath": "gopkg.in/square/go-jose.v2",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
||||||
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
"Rev": "89060dee6a84df9a4dae49f676f0c755037834f1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/yaml.v2",
|
"ImportPath": "gopkg.in/yaml.v2",
|
||||||
|
|
|
@ -8,11 +8,12 @@ matrix:
|
||||||
- go: tip
|
- go: tip
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.5
|
- '1.5.x'
|
||||||
- 1.6
|
- '1.6.x'
|
||||||
- 1.7
|
- '1.7.x'
|
||||||
- 1.8
|
- '1.8.x'
|
||||||
- 1.9
|
- '1.9.x'
|
||||||
|
- '1.10.x'
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
go_import_path: gopkg.in/square/go-jose.v2
|
go_import_path: gopkg.in/square/go-jose.v2
|
||||||
|
|
|
@ -10,6 +10,7 @@ go_library(
|
||||||
"jwe.go",
|
"jwe.go",
|
||||||
"jwk.go",
|
"jwk.go",
|
||||||
"jws.go",
|
"jws.go",
|
||||||
|
"opaque.go",
|
||||||
"shared.go",
|
"shared.go",
|
||||||
"signing.go",
|
"signing.go",
|
||||||
"symmetric.go",
|
"symmetric.go",
|
||||||
|
|
|
@ -84,6 +84,7 @@ standard where possible. The Godoc reference has a list of constants.
|
||||||
RSASSA-PSS | PS256, PS384, PS512
|
RSASSA-PSS | PS256, PS384, PS512
|
||||||
HMAC | HS256, HS384, HS512
|
HMAC | HS256, HS384, HS512
|
||||||
ECDSA | ES256, ES384, ES512
|
ECDSA | ES256, ES384, ES512
|
||||||
|
Ed25519 | EdDSA
|
||||||
|
|
||||||
Content encryption | Algorithm identifier(s)
|
Content encryption | Algorithm identifier(s)
|
||||||
:------------------------- | :------------------------------
|
:------------------------- | :------------------------------
|
||||||
|
|
|
@ -104,9 +104,9 @@ func newRSASigner(sigAlg SignatureAlgorithm, privateKey *rsa.PrivateKey) (recipi
|
||||||
|
|
||||||
return recipientSigInfo{
|
return recipientSigInfo{
|
||||||
sigAlg: sigAlg,
|
sigAlg: sigAlg,
|
||||||
publicKey: &JSONWebKey{
|
publicKey: staticPublicKey(&JSONWebKey{
|
||||||
Key: &privateKey.PublicKey,
|
Key: privateKey.Public(),
|
||||||
},
|
}),
|
||||||
signer: &rsaDecrypterSigner{
|
signer: &rsaDecrypterSigner{
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
},
|
},
|
||||||
|
@ -123,9 +123,9 @@ func newEd25519Signer(sigAlg SignatureAlgorithm, privateKey ed25519.PrivateKey)
|
||||||
}
|
}
|
||||||
return recipientSigInfo{
|
return recipientSigInfo{
|
||||||
sigAlg: sigAlg,
|
sigAlg: sigAlg,
|
||||||
publicKey: &JSONWebKey{
|
publicKey: staticPublicKey(&JSONWebKey{
|
||||||
Key: privateKey.Public(),
|
Key: privateKey.Public(),
|
||||||
},
|
}),
|
||||||
signer: &edDecrypterSigner{
|
signer: &edDecrypterSigner{
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
},
|
},
|
||||||
|
@ -168,9 +168,9 @@ func newECDSASigner(sigAlg SignatureAlgorithm, privateKey *ecdsa.PrivateKey) (re
|
||||||
|
|
||||||
return recipientSigInfo{
|
return recipientSigInfo{
|
||||||
sigAlg: sigAlg,
|
sigAlg: sigAlg,
|
||||||
publicKey: &JSONWebKey{
|
publicKey: staticPublicKey(&JSONWebKey{
|
||||||
Key: &privateKey.PublicKey,
|
Key: privateKey.Public(),
|
||||||
},
|
}),
|
||||||
signer: &ecDecrypterSigner{
|
signer: &ecDecrypterSigner{
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
},
|
},
|
||||||
|
@ -466,6 +466,7 @@ 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) {
|
func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
|
||||||
if alg != EdDSA {
|
if alg != EdDSA {
|
||||||
return Signature{}, ErrUnsupportedAlgorithm
|
return Signature{}, ErrUnsupportedAlgorithm
|
||||||
|
@ -531,7 +532,7 @@ func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm)
|
||||||
keyBytes++
|
keyBytes++
|
||||||
}
|
}
|
||||||
|
|
||||||
// We serialize the outpus (r and s) into big-endian byte arrays and pad
|
// We serialize the outputs (r and s) into big-endian byte arrays and pad
|
||||||
// them with zeros on the left to make sure the sizes work out. Both arrays
|
// them with zeros on the left to make sure the sizes work out. Both arrays
|
||||||
// must be keyBytes long, and the output must be 2*keyBytes long.
|
// must be keyBytes long, and the output must be 2*keyBytes long.
|
||||||
rBytes := r.Bytes()
|
rBytes := r.Bytes()
|
||||||
|
|
|
@ -148,17 +148,10 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
|
||||||
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, err = parseCertificateChain(raw.X5c)
|
||||||
for i, cert := range raw.X5c {
|
|
||||||
raw, err := base64.StdEncoding.DecodeString(cert)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to unmarshal x5c field: %s", err)
|
||||||
}
|
|
||||||
k.Certificates[i], err = x509.ParseCertificate(raw)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,13 +240,32 @@ func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
|
||||||
// IsPublic returns true if the JWK represents a public key (not symmetric, not private).
|
// IsPublic returns true if the JWK represents a public key (not symmetric, not private).
|
||||||
func (k *JSONWebKey) IsPublic() bool {
|
func (k *JSONWebKey) IsPublic() bool {
|
||||||
switch k.Key.(type) {
|
switch k.Key.(type) {
|
||||||
case *ecdsa.PublicKey, *rsa.PublicKey, *ed25519.PublicKey:
|
case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Public creates JSONWebKey with corresponding publik key if JWK represents asymmetric private key.
|
||||||
|
func (k *JSONWebKey) Public() JSONWebKey {
|
||||||
|
if k.IsPublic() {
|
||||||
|
return *k
|
||||||
|
}
|
||||||
|
ret := *k
|
||||||
|
switch key := k.Key.(type) {
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
ret.Key = key.Public()
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
ret.Key = key.Public()
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
ret.Key = key.Public()
|
||||||
|
default:
|
||||||
|
return JSONWebKey{} // returning invalid key
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// Valid checks that the key contains the expected parameters.
|
// Valid checks that the key contains the expected parameters.
|
||||||
func (k *JSONWebKey) Valid() bool {
|
func (k *JSONWebKey) Valid() bool {
|
||||||
if k.Key == nil {
|
if k.Key == nil {
|
||||||
|
@ -276,12 +288,12 @@ 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:
|
case ed25519.PublicKey:
|
||||||
if len(*key) != 32 {
|
if len(key) != 32 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case *ed25519.PrivateKey:
|
case ed25519.PrivateKey:
|
||||||
if len(*key) != 64 {
|
if len(key) != 64 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -52,9 +52,20 @@ type JSONWebSignature struct {
|
||||||
|
|
||||||
// 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
|
// Merged header fields. Contains both protected and unprotected header
|
||||||
|
// values. Prefer using Protected and Unprotected fields instead of this.
|
||||||
|
// Values in this header may or may not have been signed and in general
|
||||||
|
// should not be trusted.
|
||||||
Header Header
|
Header Header
|
||||||
|
|
||||||
|
// Protected header. Values in this header were signed and
|
||||||
|
// will be verified as part of the signature verification process.
|
||||||
|
Protected Header
|
||||||
|
|
||||||
|
// Unprotected header. Values in this header were not signed
|
||||||
|
// and in general should not be trusted.
|
||||||
|
Unprotected Header
|
||||||
|
|
||||||
// The actual signature value
|
// The actual signature value
|
||||||
Signature []byte
|
Signature []byte
|
||||||
|
|
||||||
|
@ -82,7 +93,7 @@ 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(payload []byte, 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 {
|
||||||
|
@ -95,7 +106,7 @@ func (obj JSONWebSignature) computeAuthData(signature *Signature) []byte {
|
||||||
|
|
||||||
return []byte(fmt.Sprintf("%s.%s",
|
return []byte(fmt.Sprintf("%s.%s",
|
||||||
serializedProtected,
|
serializedProtected,
|
||||||
base64.RawURLEncoding.EncodeToString(obj.payload)))
|
base64.RawURLEncoding.EncodeToString(payload)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSignedFull parses a message in full format.
|
// parseSignedFull parses a message in full format.
|
||||||
|
@ -159,6 +170,20 @@ func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if signature.header != nil {
|
||||||
|
signature.Unprotected, err = signature.header.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signature.protected != nil {
|
||||||
|
signature.Protected, err = signature.protected.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
|
// As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
|
||||||
jwk := signature.Header.JSONWebKey
|
jwk := signature.Header.JSONWebKey
|
||||||
if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
|
if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
|
||||||
|
@ -188,6 +213,20 @@ func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if obj.Signatures[i].header != nil {
|
||||||
|
obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Signatures[i].protected != nil {
|
||||||
|
obj.Signatures[i].Protected, err = obj.Signatures[i].protected.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.
|
// As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*-
|
||||||
|
* Copyright 2018 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
|
||||||
|
|
||||||
|
// OpaqueSigner is an interface that supports signing payloads with opaque
|
||||||
|
// private key(s). Private key operations preformed by implementors may, for
|
||||||
|
// example, occur in a hardware module. An OpaqueSigner may rotate signing keys
|
||||||
|
// transparently to the user of this interface.
|
||||||
|
type OpaqueSigner interface {
|
||||||
|
// Public returns the public key of the current signing key.
|
||||||
|
Public() *JSONWebKey
|
||||||
|
// Algs returns a list of supported signing algorithms.
|
||||||
|
Algs() []SignatureAlgorithm
|
||||||
|
// SignPayload signs a payload with the current signing key using the given
|
||||||
|
// algorithm.
|
||||||
|
SignPayload(payload []byte, alg SignatureAlgorithm) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type opaqueSigner struct {
|
||||||
|
signer OpaqueSigner
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOpaqueSigner(alg SignatureAlgorithm, signer OpaqueSigner) (recipientSigInfo, error) {
|
||||||
|
var algSupported bool
|
||||||
|
for _, salg := range signer.Algs() {
|
||||||
|
if alg == salg {
|
||||||
|
algSupported = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !algSupported {
|
||||||
|
return recipientSigInfo{}, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
return recipientSigInfo{
|
||||||
|
sigAlg: alg,
|
||||||
|
publicKey: signer.Public,
|
||||||
|
signer: &opaqueSigner{
|
||||||
|
signer: signer,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *opaqueSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
|
||||||
|
out, err := o.signer.SignPayload(payload, alg)
|
||||||
|
if err != nil {
|
||||||
|
return Signature{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Signature{
|
||||||
|
Signature: out,
|
||||||
|
protected: &rawHeader{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpaqueVerifier is an interface that supports verifying payloads with opaque
|
||||||
|
// public key(s). An OpaqueSigner may rotate signing keys transparently to the
|
||||||
|
// user of this interface.
|
||||||
|
type OpaqueVerifier interface {
|
||||||
|
VerifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type opaqueVerifier struct {
|
||||||
|
verifier OpaqueVerifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *opaqueVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
|
||||||
|
return o.verifier.VerifyPayload(payload, signature, alg)
|
||||||
|
}
|
|
@ -18,6 +18,8 @@ package jose
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -141,6 +143,7 @@ const (
|
||||||
headerEPK = "epk" // *JSONWebKey
|
headerEPK = "epk" // *JSONWebKey
|
||||||
headerIV = "iv" // *byteBuffer
|
headerIV = "iv" // *byteBuffer
|
||||||
headerTag = "tag" // *byteBuffer
|
headerTag = "tag" // *byteBuffer
|
||||||
|
headerX5c = "x5c" // []*x509.Certificate
|
||||||
|
|
||||||
headerJWK = "jwk" // *JSONWebKey
|
headerJWK = "jwk" // *JSONWebKey
|
||||||
headerKeyID = "kid" // string
|
headerKeyID = "kid" // string
|
||||||
|
@ -162,11 +165,34 @@ type Header struct {
|
||||||
Algorithm string
|
Algorithm string
|
||||||
Nonce string
|
Nonce string
|
||||||
|
|
||||||
// Any headers not recognised above get unmarshaled from JSON in a generic
|
// Unverified certificate chain parsed from x5c header.
|
||||||
// manner and placed in this map.
|
certificates []*x509.Certificate
|
||||||
|
|
||||||
|
// Any headers not recognised above get unmarshaled
|
||||||
|
// from JSON in a generic manner and placed in this map.
|
||||||
ExtraHeaders map[HeaderKey]interface{}
|
ExtraHeaders map[HeaderKey]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Certificates verifies & returns the certificate chain present
|
||||||
|
// in the x5c header field of a message, if one was present. Returns
|
||||||
|
// an error if there was no x5c header present or the chain could
|
||||||
|
// not be validated with the given verify options.
|
||||||
|
func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) {
|
||||||
|
if len(h.certificates) == 0 {
|
||||||
|
return nil, errors.New("square/go-jose: no x5c header present in message")
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf := h.certificates[0]
|
||||||
|
if opts.Intermediates == nil {
|
||||||
|
opts.Intermediates = x509.NewCertPool()
|
||||||
|
for _, intermediate := range h.certificates[1:] {
|
||||||
|
opts.Intermediates.AddCert(intermediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return leaf.Verify(opts)
|
||||||
|
}
|
||||||
|
|
||||||
func (parsed rawHeader) set(k HeaderKey, v interface{}) error {
|
func (parsed rawHeader) set(k HeaderKey, v interface{}) error {
|
||||||
b, err := json.Marshal(v)
|
b, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -333,6 +359,18 @@ func (parsed rawHeader) sanitized() (h Header, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.Nonce = s
|
h.Nonce = s
|
||||||
|
case headerX5c:
|
||||||
|
c := []string{}
|
||||||
|
err = json.Unmarshal(*v, &c)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal x5c header: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.certificates, err = parseCertificateChain(c)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to unmarshal x5c header: %v: %#v", err, string(*v))
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if h.ExtraHeaders == nil {
|
if h.ExtraHeaders == nil {
|
||||||
h.ExtraHeaders = map[HeaderKey]interface{}{}
|
h.ExtraHeaders = map[HeaderKey]interface{}{}
|
||||||
|
@ -349,6 +387,21 @@ func (parsed rawHeader) sanitized() (h Header, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseCertificateChain(chain []string) ([]*x509.Certificate, error) {
|
||||||
|
out := make([]*x509.Certificate, len(chain))
|
||||||
|
for i, cert := range chain {
|
||||||
|
raw, err := base64.StdEncoding.DecodeString(cert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out[i], err = x509.ParseCertificate(raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (dst rawHeader) isSet(k HeaderKey) bool {
|
func (dst rawHeader) isSet(k HeaderKey) bool {
|
||||||
dvr := dst[k]
|
dvr := dst[k]
|
||||||
if dvr == nil {
|
if dvr == nil {
|
||||||
|
|
|
@ -94,10 +94,16 @@ type genericSigner struct {
|
||||||
|
|
||||||
type recipientSigInfo struct {
|
type recipientSigInfo struct {
|
||||||
sigAlg SignatureAlgorithm
|
sigAlg SignatureAlgorithm
|
||||||
publicKey *JSONWebKey
|
publicKey func() *JSONWebKey
|
||||||
signer payloadSigner
|
signer payloadSigner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func staticPublicKey(jwk *JSONWebKey) func() *JSONWebKey {
|
||||||
|
return func() *JSONWebKey {
|
||||||
|
return jwk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewSigner creates an appropriate signer based on the key type
|
// NewSigner creates an appropriate signer based on the key type
|
||||||
func NewSigner(sig SigningKey, opts *SignerOptions) (Signer, error) {
|
func NewSigner(sig SigningKey, opts *SignerOptions) (Signer, error) {
|
||||||
return NewMultiSigner([]SigningKey{sig}, opts)
|
return NewMultiSigner([]SigningKey{sig}, opts)
|
||||||
|
@ -146,9 +152,11 @@ func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
|
||||||
return newVerifier(verificationKey.Key)
|
return newVerifier(verificationKey.Key)
|
||||||
case *JSONWebKey:
|
case *JSONWebKey:
|
||||||
return newVerifier(verificationKey.Key)
|
return newVerifier(verificationKey.Key)
|
||||||
default:
|
|
||||||
return nil, ErrUnsupportedKeyType
|
|
||||||
}
|
}
|
||||||
|
if ov, ok := verificationKey.(OpaqueVerifier); ok {
|
||||||
|
return &opaqueVerifier{verifier: ov}, nil
|
||||||
|
}
|
||||||
|
return nil, ErrUnsupportedKeyType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error {
|
func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error {
|
||||||
|
@ -175,9 +183,11 @@ func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipient
|
||||||
return newJWKSigner(alg, signingKey)
|
return newJWKSigner(alg, signingKey)
|
||||||
case *JSONWebKey:
|
case *JSONWebKey:
|
||||||
return newJWKSigner(alg, *signingKey)
|
return newJWKSigner(alg, *signingKey)
|
||||||
default:
|
|
||||||
return recipientSigInfo{}, ErrUnsupportedKeyType
|
|
||||||
}
|
}
|
||||||
|
if signer, ok := signingKey.(OpaqueSigner); ok {
|
||||||
|
return newOpaqueSigner(alg, signer)
|
||||||
|
}
|
||||||
|
return recipientSigInfo{}, ErrUnsupportedKeyType
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) {
|
func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) {
|
||||||
|
@ -185,16 +195,16 @@ func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigIn
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return recipientSigInfo{}, err
|
return recipientSigInfo{}, err
|
||||||
}
|
}
|
||||||
if recipient.publicKey != nil {
|
if recipient.publicKey != nil && recipient.publicKey() != nil {
|
||||||
// recipient.publicKey is a JWK synthesized for embedding when recipientSigInfo
|
// 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
|
// 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.
|
// the pub key for embedding, but doesn't have extra params like key id.
|
||||||
publicKey := signingKey
|
publicKey := signingKey
|
||||||
publicKey.Key = recipient.publicKey.Key
|
publicKey.Key = recipient.publicKey().Key
|
||||||
recipient.publicKey = &publicKey
|
recipient.publicKey = staticPublicKey(&publicKey)
|
||||||
|
|
||||||
// This should be impossible, but let's check anyway.
|
// This should be impossible, but let's check anyway.
|
||||||
if !recipient.publicKey.IsPublic() {
|
if !recipient.publicKey().IsPublic() {
|
||||||
return recipientSigInfo{}, errors.New("square/go-jose: public key was unexpectedly not public")
|
return recipientSigInfo{}, errors.New("square/go-jose: public key was unexpectedly not public")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +221,7 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
|
||||||
headerAlgorithm: string(recipient.sigAlg),
|
headerAlgorithm: string(recipient.sigAlg),
|
||||||
}
|
}
|
||||||
|
|
||||||
if recipient.publicKey != nil {
|
if recipient.publicKey != nil && recipient.publicKey() != nil {
|
||||||
// We want to embed the JWK or set the kid header, but not both. Having a protected
|
// 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 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
|
// header is confusing, and at least in ACME the two are considered to be mutually
|
||||||
|
@ -221,9 +231,9 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
|
||||||
//
|
//
|
||||||
// See https://github.com/square/go-jose/issues/157 for more context.
|
// See https://github.com/square/go-jose/issues/157 for more context.
|
||||||
if ctx.embedJWK {
|
if ctx.embedJWK {
|
||||||
protected[headerJWK] = recipient.publicKey
|
protected[headerJWK] = recipient.publicKey()
|
||||||
} else {
|
} else {
|
||||||
protected[headerKeyID] = recipient.publicKey.KeyID
|
protected[headerKeyID] = recipient.publicKey().KeyID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,34 +290,46 @@ func (ctx *genericSigner) Options() SignerOptions {
|
||||||
// payload header. You cannot assume that the key received in a payload is
|
// payload header. You cannot assume that the key received in a payload is
|
||||||
// trusted.
|
// trusted.
|
||||||
func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
|
func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
|
||||||
verifier, err := newVerifier(verificationKey)
|
err := obj.DetachedVerify(obj.payload, verificationKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return obj.payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetachedVerify validates a detached signature on the given payload. In
|
||||||
|
// most cases, you will probably want to use Verify instead. DetachedVerify
|
||||||
|
// is only useful if you have a payload and signature that are separated from
|
||||||
|
// each other.
|
||||||
|
func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error {
|
||||||
|
verifier, err := newVerifier(verificationKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if len(obj.Signatures) > 1 {
|
if len(obj.Signatures) > 1 {
|
||||||
return nil, errors.New("square/go-jose: too many signatures in payload; expecting only one")
|
return errors.New("square/go-jose: too many signatures in payload; expecting only one")
|
||||||
}
|
}
|
||||||
|
|
||||||
signature := obj.Signatures[0]
|
signature := obj.Signatures[0]
|
||||||
headers := signature.mergedHeaders()
|
headers := signature.mergedHeaders()
|
||||||
critical, err := headers.getCritical()
|
critical, err := headers.getCritical()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
if len(critical) > 0 {
|
if len(critical) > 0 {
|
||||||
// Unsupported crit header
|
// Unsupported crit header
|
||||||
return nil, ErrCryptoFailure
|
return ErrCryptoFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
input := obj.computeAuthData(&signature)
|
input := obj.computeAuthData(payload, &signature)
|
||||||
alg := headers.getSignatureAlgorithm()
|
alg := headers.getSignatureAlgorithm()
|
||||||
err = verifier.verifyPayload(input, signature.Signature, alg)
|
err = verifier.verifyPayload(input, signature.Signature, alg)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return obj.payload, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrCryptoFailure
|
return ErrCryptoFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyMulti validates (one of the multiple) signatures on the object and
|
// VerifyMulti validates (one of the multiple) signatures on the object and
|
||||||
|
@ -315,10 +337,27 @@ func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error)
|
||||||
// object and the payload. We return the signature and index to guarantee that
|
// object and the payload. We return the signature and index to guarantee that
|
||||||
// callers are getting the verified value.
|
// callers are getting the verified value.
|
||||||
func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) {
|
func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) {
|
||||||
verifier, err := newVerifier(verificationKey)
|
idx, sig, err := obj.DetachedVerifyMulti(obj.payload, verificationKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, Signature{}, nil, err
|
return -1, Signature{}, nil, err
|
||||||
}
|
}
|
||||||
|
return idx, sig, obj.payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetachedVerifyMulti validates a detached signature on the given payload with
|
||||||
|
// a signature/object that has potentially multiple signers. This returns the index
|
||||||
|
// of the signature that was verified, along with the signature object. We return
|
||||||
|
// the signature and index to guarantee that callers are getting the verified value.
|
||||||
|
//
|
||||||
|
// In most cases, you will probably want to use Verify or VerifyMulti instead.
|
||||||
|
// DetachedVerifyMulti is only useful if you have a payload and signature that are
|
||||||
|
// separated from each other, and the signature can have multiple signers at the
|
||||||
|
// same time.
|
||||||
|
func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) {
|
||||||
|
verifier, err := newVerifier(verificationKey)
|
||||||
|
if err != nil {
|
||||||
|
return -1, Signature{}, err
|
||||||
|
}
|
||||||
|
|
||||||
for i, signature := range obj.Signatures {
|
for i, signature := range obj.Signatures {
|
||||||
headers := signature.mergedHeaders()
|
headers := signature.mergedHeaders()
|
||||||
|
@ -331,13 +370,13 @@ func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signa
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
input := obj.computeAuthData(&signature)
|
input := obj.computeAuthData(payload, &signature)
|
||||||
alg := headers.getSignatureAlgorithm()
|
alg := headers.getSignatureAlgorithm()
|
||||||
err = verifier.verifyPayload(input, signature.Signature, alg)
|
err = verifier.verifyPayload(input, signature.Signature, alg)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return i, signature, obj.payload, nil
|
return i, signature, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, Signature{}, nil, ErrCryptoFailure
|
return -1, Signature{}, ErrCryptoFailure
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue