1 package jwk
2
3 import (
4 "bytes"
5 "crypto"
6 "crypto/ed25519"
7 "fmt"
8
9 "github.com/lestrrat-go/blackmagic"
10 "github.com/lestrrat-go/jwx/internal/base64"
11 "github.com/lestrrat-go/jwx/jwa"
12 "github.com/lestrrat-go/jwx/x25519"
13 "github.com/pkg/errors"
14 )
15
16 func (k *okpPublicKey) FromRaw(rawKeyIf interface{}) error {
17 k.mu.Lock()
18 defer k.mu.Unlock()
19
20 var crv jwa.EllipticCurveAlgorithm
21 switch rawKey := rawKeyIf.(type) {
22 case ed25519.PublicKey:
23 k.x = rawKey
24 crv = jwa.Ed25519
25 k.crv = &crv
26 case x25519.PublicKey:
27 k.x = rawKey
28 crv = jwa.X25519
29 k.crv = &crv
30 default:
31 return errors.Errorf(`unknown key type %T`, rawKeyIf)
32 }
33
34 return nil
35 }
36
37 func (k *okpPrivateKey) FromRaw(rawKeyIf interface{}) error {
38 k.mu.Lock()
39 defer k.mu.Unlock()
40
41 var crv jwa.EllipticCurveAlgorithm
42 switch rawKey := rawKeyIf.(type) {
43 case ed25519.PrivateKey:
44 k.d = rawKey.Seed()
45 k.x = rawKey.Public().(ed25519.PublicKey)
46 crv = jwa.Ed25519
47 k.crv = &crv
48 case x25519.PrivateKey:
49 k.d = rawKey.Seed()
50 k.x = rawKey.Public().(x25519.PublicKey)
51 crv = jwa.X25519
52 k.crv = &crv
53 default:
54 return errors.Errorf(`unknown key type %T`, rawKeyIf)
55 }
56
57 return nil
58 }
59
60 func buildOKPPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf []byte) (interface{}, error) {
61 switch alg {
62 case jwa.Ed25519:
63 return ed25519.PublicKey(xbuf), nil
64 case jwa.X25519:
65 return x25519.PublicKey(xbuf), nil
66 default:
67 return nil, errors.Errorf(`invalid curve algorithm %s`, alg)
68 }
69 }
70
71
72 func (k *okpPublicKey) Raw(v interface{}) error {
73 k.mu.RLock()
74 defer k.mu.RUnlock()
75
76 pubk, err := buildOKPPublicKey(k.Crv(), k.x)
77 if err != nil {
78 return errors.Wrap(err, `failed to build public key`)
79 }
80
81 return blackmagic.AssignIfCompatible(v, pubk)
82 }
83
84 func buildOKPPrivateKey(alg jwa.EllipticCurveAlgorithm, xbuf []byte, dbuf []byte) (interface{}, error) {
85 switch alg {
86 case jwa.Ed25519:
87 ret := ed25519.NewKeyFromSeed(dbuf)
88
89 if !bytes.Equal(xbuf, ret.Public().(ed25519.PublicKey)) {
90 return nil, errors.Errorf(`invalid x value given d value`)
91 }
92 return ret, nil
93 case jwa.X25519:
94 ret, err := x25519.NewKeyFromSeed(dbuf)
95 if err != nil {
96 return nil, errors.Wrap(err, `unable to construct x25519 private key from seed`)
97 }
98
99 if !bytes.Equal(xbuf, ret.Public().(x25519.PublicKey)) {
100 return nil, errors.Errorf(`invalid x value given d value`)
101 }
102 return ret, nil
103 default:
104 return nil, errors.Errorf(`invalid curve algorithm %s`, alg)
105 }
106 }
107
108 func (k *okpPrivateKey) Raw(v interface{}) error {
109 k.mu.RLock()
110 defer k.mu.RUnlock()
111
112 privk, err := buildOKPPrivateKey(k.Crv(), k.x, k.d)
113 if err != nil {
114 return errors.Wrap(err, `failed to build public key`)
115 }
116
117 return blackmagic.AssignIfCompatible(v, privk)
118 }
119
120 func makeOKPPublicKey(v interface {
121 makePairs() []*HeaderPair
122 }) (Key, error) {
123 newKey := NewOKPPublicKey()
124
125
126 for _, pair := range v.makePairs() {
127 switch pair.Key {
128 case OKPDKey:
129 continue
130 default:
131
132 key := pair.Key.(string)
133 if err := newKey.Set(key, pair.Value); err != nil {
134 return nil, errors.Wrapf(err, `failed to set field %q`, key)
135 }
136 }
137 }
138
139 return newKey, nil
140 }
141
142 func (k *okpPrivateKey) PublicKey() (Key, error) {
143 return makeOKPPublicKey(k)
144 }
145
146 func (k *okpPublicKey) PublicKey() (Key, error) {
147 return makeOKPPublicKey(k)
148 }
149
150 func okpThumbprint(hash crypto.Hash, crv, x string) []byte {
151 h := hash.New()
152 fmt.Fprint(h, `{"crv":"`)
153 fmt.Fprint(h, crv)
154 fmt.Fprint(h, `","kty":"OKP","x":"`)
155 fmt.Fprint(h, x)
156 fmt.Fprint(h, `"}`)
157 return h.Sum(nil)
158 }
159
160
161
162 func (k okpPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
163 k.mu.RLock()
164 defer k.mu.RUnlock()
165
166 return okpThumbprint(
167 hash,
168 k.Crv().String(),
169 base64.EncodeToString(k.x),
170 ), nil
171 }
172
173
174
175 func (k okpPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
176 k.mu.RLock()
177 defer k.mu.RUnlock()
178
179 return okpThumbprint(
180 hash,
181 k.Crv().String(),
182 base64.EncodeToString(k.x),
183 ), nil
184 }
185
View as plain text