Update gopkg.in/go-jose.v2 to v2.1.3. (#3087)
The 2.1.3 release of go-jose.v2 contains a bug fix for a nil panic encountering null values in JWS headers that affects Boulder. This commit updates Boulder to use the 2.1.3 release. Unit tests were confirmed to pass: ``` $ go test ./... ok gopkg.in/square/go-jose.v2 13.648s ok gopkg.in/square/go-jose.v2/cipher 0.003s ? gopkg.in/square/go-jose.v2/jose-util [no test files] ok gopkg.in/square/go-jose.v2/json 1.199s ok gopkg.in/square/go-jose.v2/jwt 0.064s ```
This commit is contained in:
parent
254537ea48
commit
0e4466bb30
|
@ -249,6 +249,14 @@
|
||||||
"Comment": "v0.3.2-21-g6787cd3",
|
"Comment": "v0.3.2-21-g6787cd3",
|
||||||
"Rev": "6787cd3b348b18fab6371264ae5392cd8eca1723"
|
"Rev": "6787cd3b348b18fab6371264ae5392cd8eca1723"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/ed25519",
|
||||||
|
"Rev": "7c6cc321c680f03b9ef0764448e780704f486b51"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
||||||
|
"Rev": "7c6cc321c680f03b9ef0764448e780704f486b51"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ocsp",
|
"ImportPath": "golang.org/x/crypto/ocsp",
|
||||||
"Rev": "7c6cc321c680f03b9ef0764448e780704f486b51"
|
"Rev": "7c6cc321c680f03b9ef0764448e780704f486b51"
|
||||||
|
@ -376,18 +384,18 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2",
|
"ImportPath": "gopkg.in/square/go-jose.v2",
|
||||||
"Comment": "v2.1.0",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "d5683d954d08cd430460c651e2a2fff4f3b39f86"
|
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
"ImportPath": "gopkg.in/square/go-jose.v2/cipher",
|
||||||
"Comment": "v2.1.0",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "d5683d954d08cd430460c651e2a2fff4f3b39f86"
|
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
"ImportPath": "gopkg.in/square/go-jose.v2/json",
|
||||||
"Comment": "v2.1.0",
|
"Comment": "v2.1.3",
|
||||||
"Rev": "d5683d954d08cd430460c651e2a2fff4f3b39f86"
|
"Rev": "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/yaml.v2",
|
"ImportPath": "gopkg.in/yaml.v2",
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package ed25519 implements the Ed25519 signature algorithm. See
|
||||||
|
// http://ed25519.cr.yp.to/.
|
||||||
|
//
|
||||||
|
// These functions are also compatible with the “Ed25519” function defined in
|
||||||
|
// https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05.
|
||||||
|
package ed25519
|
||||||
|
|
||||||
|
// This code is a port of the public domain, “ref10” implementation of ed25519
|
||||||
|
// from SUPERCOP.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
cryptorand "crypto/rand"
|
||||||
|
"crypto/sha512"
|
||||||
|
"crypto/subtle"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ed25519/internal/edwards25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
||||||
|
PublicKeySize = 32
|
||||||
|
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
||||||
|
PrivateKeySize = 64
|
||||||
|
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||||
|
SignatureSize = 64
|
||||||
|
)
|
||||||
|
|
||||||
|
// PublicKey is the type of Ed25519 public keys.
|
||||||
|
type PublicKey []byte
|
||||||
|
|
||||||
|
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
||||||
|
type PrivateKey []byte
|
||||||
|
|
||||||
|
// Public returns the PublicKey corresponding to priv.
|
||||||
|
func (priv PrivateKey) Public() crypto.PublicKey {
|
||||||
|
publicKey := make([]byte, PublicKeySize)
|
||||||
|
copy(publicKey, priv[32:])
|
||||||
|
return PublicKey(publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs the given message with priv.
|
||||||
|
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
||||||
|
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
||||||
|
// indicate the message hasn't been hashed. This can be achieved by passing
|
||||||
|
// crypto.Hash(0) as the value for opts.
|
||||||
|
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||||
|
if opts.HashFunc() != crypto.Hash(0) {
|
||||||
|
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sign(priv, message), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||||
|
// If rand is nil, crypto/rand.Reader will be used.
|
||||||
|
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
|
||||||
|
if rand == nil {
|
||||||
|
rand = cryptorand.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey = make([]byte, PrivateKeySize)
|
||||||
|
publicKey = make([]byte, PublicKeySize)
|
||||||
|
_, err = io.ReadFull(rand, privateKey[:32])
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
digest := sha512.Sum512(privateKey[:32])
|
||||||
|
digest[0] &= 248
|
||||||
|
digest[31] &= 127
|
||||||
|
digest[31] |= 64
|
||||||
|
|
||||||
|
var A edwards25519.ExtendedGroupElement
|
||||||
|
var hBytes [32]byte
|
||||||
|
copy(hBytes[:], digest[:])
|
||||||
|
edwards25519.GeScalarMultBase(&A, &hBytes)
|
||||||
|
var publicKeyBytes [32]byte
|
||||||
|
A.ToBytes(&publicKeyBytes)
|
||||||
|
|
||||||
|
copy(privateKey[32:], publicKeyBytes[:])
|
||||||
|
copy(publicKey, publicKeyBytes[:])
|
||||||
|
|
||||||
|
return publicKey, privateKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs the message with privateKey and returns a signature. It will
|
||||||
|
// panic if len(privateKey) is not PrivateKeySize.
|
||||||
|
func Sign(privateKey PrivateKey, message []byte) []byte {
|
||||||
|
if l := len(privateKey); l != PrivateKeySize {
|
||||||
|
panic("ed25519: bad private key length: " + strconv.Itoa(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
h := sha512.New()
|
||||||
|
h.Write(privateKey[:32])
|
||||||
|
|
||||||
|
var digest1, messageDigest, hramDigest [64]byte
|
||||||
|
var expandedSecretKey [32]byte
|
||||||
|
h.Sum(digest1[:0])
|
||||||
|
copy(expandedSecretKey[:], digest1[:])
|
||||||
|
expandedSecretKey[0] &= 248
|
||||||
|
expandedSecretKey[31] &= 63
|
||||||
|
expandedSecretKey[31] |= 64
|
||||||
|
|
||||||
|
h.Reset()
|
||||||
|
h.Write(digest1[32:])
|
||||||
|
h.Write(message)
|
||||||
|
h.Sum(messageDigest[:0])
|
||||||
|
|
||||||
|
var messageDigestReduced [32]byte
|
||||||
|
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
|
||||||
|
var R edwards25519.ExtendedGroupElement
|
||||||
|
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
|
||||||
|
|
||||||
|
var encodedR [32]byte
|
||||||
|
R.ToBytes(&encodedR)
|
||||||
|
|
||||||
|
h.Reset()
|
||||||
|
h.Write(encodedR[:])
|
||||||
|
h.Write(privateKey[32:])
|
||||||
|
h.Write(message)
|
||||||
|
h.Sum(hramDigest[:0])
|
||||||
|
var hramDigestReduced [32]byte
|
||||||
|
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
|
||||||
|
|
||||||
|
var s [32]byte
|
||||||
|
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
|
||||||
|
|
||||||
|
signature := make([]byte, SignatureSize)
|
||||||
|
copy(signature[:], encodedR[:])
|
||||||
|
copy(signature[32:], s[:])
|
||||||
|
|
||||||
|
return signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify reports whether sig is a valid signature of message by publicKey. It
|
||||||
|
// will panic if len(publicKey) is not PublicKeySize.
|
||||||
|
func Verify(publicKey PublicKey, message, sig []byte) bool {
|
||||||
|
if l := len(publicKey); l != PublicKeySize {
|
||||||
|
panic("ed25519: bad public key length: " + strconv.Itoa(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sig) != SignatureSize || sig[63]&224 != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var A edwards25519.ExtendedGroupElement
|
||||||
|
var publicKeyBytes [32]byte
|
||||||
|
copy(publicKeyBytes[:], publicKey)
|
||||||
|
if !A.FromBytes(&publicKeyBytes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
edwards25519.FeNeg(&A.X, &A.X)
|
||||||
|
edwards25519.FeNeg(&A.T, &A.T)
|
||||||
|
|
||||||
|
h := sha512.New()
|
||||||
|
h.Write(sig[:32])
|
||||||
|
h.Write(publicKey[:])
|
||||||
|
h.Write(message)
|
||||||
|
var digest [64]byte
|
||||||
|
h.Sum(digest[:0])
|
||||||
|
|
||||||
|
var hReduced [32]byte
|
||||||
|
edwards25519.ScReduce(&hReduced, &digest)
|
||||||
|
|
||||||
|
var R edwards25519.ProjectiveGroupElement
|
||||||
|
var b [32]byte
|
||||||
|
copy(b[:], sig[32:])
|
||||||
|
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
|
||||||
|
|
||||||
|
var checkR [32]byte
|
||||||
|
R.ToBytes(&checkR)
|
||||||
|
return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1
|
||||||
|
}
|
1422
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
1422
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1771
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
1771
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,8 @@ go:
|
||||||
- 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
|
go_import_path: gopkg.in/square/go-jose.v2
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
"gopkg.in/square/go-jose.v2/cipher"
|
"gopkg.in/square/go-jose.v2/cipher"
|
||||||
"gopkg.in/square/go-jose.v2/json"
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
)
|
)
|
||||||
|
@ -47,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
|
||||||
|
@ -59,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
|
||||||
|
@ -104,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
|
||||||
|
@ -438,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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -29,6 +29,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
|
|
||||||
"gopkg.in/square/go-jose.v2/json"
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -73,10 +75,14 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
|
||||||
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:
|
||||||
|
@ -126,6 +132,16 @@ 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)
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -220,7 +247,7 @@ 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:
|
case *ecdsa.PublicKey, *rsa.PublicKey, *ed25519.PublicKey:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -249,6 +276,14 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -266,6 +301,14 @@ func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
|
||||||
|
return &rawJSONWebKey{
|
||||||
|
Kty: "OKP",
|
||||||
|
Crv: "Ed25519",
|
||||||
|
X: newBuffer(pub),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
|
func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
|
||||||
return &rawJSONWebKey{
|
return &rawJSONWebKey{
|
||||||
Kty: "RSA",
|
Kty: "RSA",
|
||||||
|
@ -334,6 +377,36 @@ func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJSONWebKey, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
||||||
var missing []string
|
var missing []string
|
||||||
switch {
|
switch {
|
||||||
|
@ -379,6 +452,13 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
||||||
return rv, err
|
return rv, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func fromRsaPrivateKey(rsa *rsa.PrivateKey) (*rawJSONWebKey, error) {
|
||||||
if len(rsa.Primes) != 2 {
|
if len(rsa.Primes) != 2 {
|
||||||
return nil, ErrUnsupportedKeyType
|
return nil, ErrUnsupportedKeyType
|
||||||
|
|
|
@ -68,6 +68,7 @@ var (
|
||||||
|
|
||||||
// Key management algorithms
|
// Key management algorithms
|
||||||
const (
|
const (
|
||||||
|
ED25519 = KeyAlgorithm("ED25519")
|
||||||
RSA1_5 = KeyAlgorithm("RSA1_5") // RSA-PKCS1v1.5
|
RSA1_5 = KeyAlgorithm("RSA1_5") // RSA-PKCS1v1.5
|
||||||
RSA_OAEP = KeyAlgorithm("RSA-OAEP") // RSA-OAEP-SHA1
|
RSA_OAEP = KeyAlgorithm("RSA-OAEP") // RSA-OAEP-SHA1
|
||||||
RSA_OAEP_256 = KeyAlgorithm("RSA-OAEP-256") // RSA-OAEP-SHA256
|
RSA_OAEP_256 = KeyAlgorithm("RSA-OAEP-256") // RSA-OAEP-SHA256
|
||||||
|
@ -89,6 +90,7 @@ const (
|
||||||
|
|
||||||
// Signature algorithms
|
// Signature algorithms
|
||||||
const (
|
const (
|
||||||
|
EdDSA = SignatureAlgorithm("EdDSA")
|
||||||
HS256 = SignatureAlgorithm("HS256") // HMAC using SHA-256
|
HS256 = SignatureAlgorithm("HS256") // HMAC using SHA-256
|
||||||
HS384 = SignatureAlgorithm("HS384") // HMAC using SHA-384
|
HS384 = SignatureAlgorithm("HS384") // HMAC using SHA-384
|
||||||
HS512 = SignatureAlgorithm("HS512") // HMAC using SHA-512
|
HS512 = SignatureAlgorithm("HS512") // HMAC using SHA-512
|
||||||
|
@ -295,6 +297,9 @@ func (parsed rawHeader) getCritical() ([]string, error) {
|
||||||
// sanitized produces a cleaned-up header object from the raw JSON.
|
// sanitized produces a cleaned-up header object from the raw JSON.
|
||||||
func (parsed rawHeader) sanitized() (h Header, err error) {
|
func (parsed rawHeader) sanitized() (h Header, err error) {
|
||||||
for k, v := range parsed {
|
for k, v := range parsed {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
switch k {
|
switch k {
|
||||||
case headerJWK:
|
case headerJWK:
|
||||||
var jwk *JSONWebKey
|
var jwk *JSONWebKey
|
||||||
|
|
|
@ -23,6 +23,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
|
|
||||||
"gopkg.in/square/go-jose.v2/json"
|
"gopkg.in/square/go-jose.v2/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -124,6 +126,10 @@ func NewMultiSigner(sigs []SigningKey, opts *SignerOptions) (Signer, error) {
|
||||||
// newVerifier creates a verifier based on the key type
|
// newVerifier creates a verifier based on the key type
|
||||||
func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
|
func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
|
||||||
switch verificationKey := verificationKey.(type) {
|
switch verificationKey := verificationKey.(type) {
|
||||||
|
case ed25519.PublicKey:
|
||||||
|
return &edEncrypterVerifier{
|
||||||
|
publicKey: verificationKey,
|
||||||
|
}, nil
|
||||||
case *rsa.PublicKey:
|
case *rsa.PublicKey:
|
||||||
return &rsaEncrypterVerifier{
|
return &rsaEncrypterVerifier{
|
||||||
publicKey: verificationKey,
|
publicKey: verificationKey,
|
||||||
|
@ -157,6 +163,8 @@ func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interf
|
||||||
|
|
||||||
func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipientSigInfo, error) {
|
func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipientSigInfo, error) {
|
||||||
switch signingKey := signingKey.(type) {
|
switch signingKey := signingKey.(type) {
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
return newEd25519Signer(alg, signingKey)
|
||||||
case *rsa.PrivateKey:
|
case *rsa.PrivateKey:
|
||||||
return newRSASigner(alg, signingKey)
|
return newRSASigner(alg, signingKey)
|
||||||
case *ecdsa.PrivateKey:
|
case *ecdsa.PrivateKey:
|
||||||
|
@ -177,11 +185,17 @@ func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigIn
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return recipientSigInfo{}, err
|
return recipientSigInfo{}, err
|
||||||
}
|
}
|
||||||
if signingKey.IsPublic() {
|
if recipient.publicKey != nil {
|
||||||
recipient.publicKey.KeyID = signingKey.KeyID
|
// recipient.publicKey is a JWK synthesized for embedding when recipientSigInfo
|
||||||
} else {
|
// was created for the inner key (such as a RSA or ECDSA public key). It contains
|
||||||
recipient.publicKey = &JSONWebKey{
|
// the pub key for embedding, but doesn't have extra params like key id.
|
||||||
KeyID: signingKey.KeyID,
|
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
|
return recipient, nil
|
||||||
|
@ -198,10 +212,19 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if recipient.publicKey != nil {
|
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 {
|
if ctx.embedJWK {
|
||||||
protected[headerJWK] = recipient.publicKey
|
protected[headerJWK] = recipient.publicKey
|
||||||
|
} else {
|
||||||
|
protected[headerKeyID] = recipient.publicKey.KeyID
|
||||||
}
|
}
|
||||||
protected[headerKeyID] = recipient.publicKey.KeyID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.nonceSource != nil {
|
if ctx.nonceSource != nil {
|
||||||
|
|
Loading…
Reference in New Issue