lestrrat-go / jwx
Showing 3 of 6 files from the diff.

@@ -52,11 +52,22 @@
Loading
52 52
	}
53 53
54 54
	var pubkey ed25519.PublicKey
55 -
	if err := keyconv.Ed25519PublicKey(&pubkey, key); err != nil {
56 -
		return errors.Wrapf(err, `failed to retrieve ed25519.PublicKey out of %T`, key)
55 +
	signer, ok := key.(crypto.Signer)
56 +
	if ok {
57 +
		v := signer.Public()
58 +
		pubkey, ok = v.(ed25519.PublicKey)
59 +
		if !ok {
60 +
			return errors.Errorf(`expected crypto.Signer.Public() to return ed25519.PublicKey, but got %T`, v)
61 +
		}
62 +
	} else {
63 +
		if err := keyconv.Ed25519PublicKey(&pubkey, key); err != nil {
64 +
			return errors.Wrapf(err, `failed to retrieve ed25519.PublicKey out of %T`, key)
65 +
		}
57 66
	}
67 +
58 68
	if !ed25519.Verify(pubkey, payload, signature) {
59 69
		return errors.New(`failed to match EdDSA signature`)
60 70
	}
71 +
61 72
	return nil
62 73
}

@@ -4,7 +4,9 @@
Loading
4 4
	"crypto"
5 5
	"crypto/ecdsa"
6 6
	"crypto/rand"
7 -
	"io"
7 +
	"encoding/asn1"
8 +
	"fmt"
9 +
	"math/big"
8 10
9 11
	"github.com/lestrrat-go/jwx/internal/keyconv"
10 12
	"github.com/lestrrat-go/jwx/internal/pool"
@@ -47,61 +49,76 @@
Loading
47 49
	hash crypto.Hash
48 50
}
49 51
50 -
func (s ecdsaSigner) Algorithm() jwa.SignatureAlgorithm {
51 -
	return s.alg
52 +
func (es ecdsaSigner) Algorithm() jwa.SignatureAlgorithm {
53 +
	return es.alg
52 54
}
53 55
54 -
type ecdsaCryptoSigner struct {
55 -
	key  *ecdsa.PrivateKey
56 -
	hash crypto.Hash
57 -
}
58 -
59 -
func (s *ecdsaSigner) Sign(payload []byte, key interface{}) ([]byte, error) {
56 +
func (es *ecdsaSigner) Sign(payload []byte, key interface{}) ([]byte, error) {
60 57
	if key == nil {
61 58
		return nil, errors.New(`missing private key while signing payload`)
62 59
	}
63 60
61 +
	h := es.hash.New()
62 +
	if _, err := h.Write(payload); err != nil {
63 +
		return nil, errors.Wrap(err, "failed to write payload using ecdsa")
64 +
	}
65 +
64 66
	signer, ok := key.(crypto.Signer)
65 67
	if ok {
66 -
		// We support crypto.Signer, but we DON'T support
67 -
		// ecdsa.PrivateKey as a crypto.Signer, because it encodes
68 -
		// the result in ASN1 format.
69 -
		if pk, ok := key.(*ecdsa.PrivateKey); ok {
70 -
			signer = newECDSACryptoSigner(pk, s.hash)
68 +
		switch key.(type) {
69 +
		case ecdsa.PrivateKey, *ecdsa.PrivateKey:
70 +
			// if it's a ecdsa.PrivateKey, it's more efficient to
71 +
			// go through the non-crypto.Signer route. Set ok to false
72 +
			ok = false
71 73
		}
72 -
	} else {
73 -
		var privkey ecdsa.PrivateKey
74 -
		if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil {
75 -
			return nil, errors.Wrapf(err, `failed to retrieve ecdsa.PrivateKey out of %T`, key)
76 -
		}
77 -
		signer = newECDSACryptoSigner(&privkey, s.hash)
78 74
	}
79 75
80 -
	h := s.hash.New()
81 -
	if _, err := h.Write(payload); err != nil {
82 -
		return nil, errors.Wrap(err, "failed to write payload using ecdsa")
83 -
	}
84 -
	return signer.Sign(rand.Reader, h.Sum(nil), s.hash)
85 -
}
76 +
	var r, s *big.Int
77 +
	var curveBits int
78 +
	if ok {
79 +
		signed, err := signer.Sign(rand.Reader, h.Sum(nil), es.hash)
80 +
		if err != nil {
81 +
			return nil, err
82 +
		}
86 83
87 -
func newECDSACryptoSigner(key *ecdsa.PrivateKey, hash crypto.Hash) crypto.Signer {
88 -
	return &ecdsaCryptoSigner{
89 -
		key:  key,
90 -
		hash: hash,
91 -
	}
92 -
}
84 +
		var p struct {
85 +
			R *big.Int
86 +
			S *big.Int
87 +
		}
88 +
		if _, err := asn1.Unmarshal(signed, &p); err != nil {
89 +
			return nil, errors.Wrap(err, `failed to unmarshal ASN1 encoded signature`)
90 +
		}
93 91
94 -
func (cs *ecdsaCryptoSigner) Public() crypto.PublicKey {
95 -
	return cs.key.PublicKey
96 -
}
92 +
		// Okay, this is silly, but hear me out. When we use the
93 +
		// crypto.Signer interface, the PrivateKey is hidden.
94 +
		// But we need some information about the key (it's bit size).
95 +
		//
96 +
		// So while silly, we're going to have to make another call
97 +
		// here and fetch the Public key.
98 +
		// This probably means that this should be cached some where.
99 +
		cpub := signer.Public()
100 +
		pubkey, ok := cpub.(*ecdsa.PublicKey)
101 +
		if !ok {
102 +
			return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey)
103 +
		}
104 +
		curveBits = pubkey.Curve.Params().BitSize
97 105
98 -
func (cs *ecdsaCryptoSigner) Sign(seed io.Reader, digest []byte, _ crypto.SignerOpts) ([]byte, error) {
99 -
	r, s, err := ecdsa.Sign(seed, cs.key, digest)
100 -
	if err != nil {
101 -
		return nil, errors.Wrap(err, "failed to sign payload using ecdsa")
106 +
		r = p.R
107 +
		s = p.S
108 +
	} else {
109 +
		var privkey ecdsa.PrivateKey
110 +
		if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil {
111 +
			return nil, errors.Wrapf(err, `failed to retrieve ecdsa.PrivateKey out of %T`, key)
112 +
		}
113 +
		curveBits = privkey.Curve.Params().BitSize
114 +
		rtmp, stmp, err := ecdsa.Sign(rand.Reader, &privkey, h.Sum(nil))
115 +
		if err != nil {
116 +
			return nil, errors.Wrap(err, "failed to sign payload using ecdsa")
117 +
		}
118 +
		r = rtmp
119 +
		s = stmp
102 120
	}
103 121
104 -
	curveBits := cs.key.Curve.Params().BitSize
105 122
	keyBytes := curveBits / 8
106 123
	// Curve bits do not need to be a multiple of 8.
107 124
	if curveBits%8 > 0 {
@@ -140,8 +157,20 @@
Loading
140 157
	}
141 158
142 159
	var pubkey ecdsa.PublicKey
143 -
	if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil {
144 -
		return errors.Wrapf(err, `failed to retrieve ecdsa.PublicKey out of %T`, key)
160 +
	if cs, ok := key.(crypto.Signer); ok {
161 +
		cpub := cs.Public()
162 +
		switch cpub := cpub.(type) {
163 +
		case ecdsa.PublicKey:
164 +
			pubkey = cpub
165 +
		case *ecdsa.PublicKey:
166 +
			pubkey = *cpub
167 +
		default:
168 +
			return errors.Errorf(`failed to retrieve ecdsa.PublicKey out of crypto.Signer %T`, key)
169 +
		}
170 +
	} else {
171 +
		if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil {
172 +
			return errors.Wrapf(err, `failed to retrieve ecdsa.PublicKey out of %T`, key)
173 +
		}
145 174
	}
146 175
147 176
	r := pool.GetBigInt()

@@ -114,8 +114,20 @@
Loading
114 114
	}
115 115
116 116
	var pubkey rsa.PublicKey
117 -
	if err := keyconv.RSAPublicKey(&pubkey, key); err != nil {
118 -
		return errors.Wrapf(err, `failed to retrieve rsa.PublicKey out of %T`, key)
117 +
	if cs, ok := key.(crypto.Signer); ok {
118 +
		cpub := cs.Public()
119 +
		switch cpub := cpub.(type) {
120 +
		case rsa.PublicKey:
121 +
			pubkey = cpub
122 +
		case *rsa.PublicKey:
123 +
			pubkey = *cpub
124 +
		default:
125 +
			return errors.Errorf(`failed to retrieve rsa.PublicKey out of crypto.Signer %T`, key)
126 +
		}
127 +
	} else {
128 +
		if err := keyconv.RSAPublicKey(&pubkey, key); err != nil {
129 +
			return errors.Wrapf(err, `failed to retrieve rsa.PublicKey out of %T`, key)
130 +
		}
119 131
	}
120 132
121 133
	h := rv.hash.New()
Files Coverage
internal 80.92%
jwa 100.00%
jwe 64.16%
jwk 73.44%
jws 74.78%
jwt 74.56%
cmd/jwx/jwx.go 100.00%
format.go 84.62%
formatkind_string_gen.go 100.00%
options.go 66.67%
x25519/x25519.go 82.35%
Project Totals (84 files) 72.66%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading