@@ -4,13 +4,16 @@ import (
44 "crypto/ecdh"
55 "crypto/ecdsa"
66 "crypto/ed25519"
7+ "crypto/elliptic"
78 "crypto/rsa"
89 "errors"
910 "fmt"
11+ "math/big"
1012 "reflect"
1113 "sync"
1214
1315 "github.com/lestrrat-go/blackmagic"
16+ "github.com/lestrrat-go/jwx/v3/internal/ecutil"
1417 "github.com/lestrrat-go/jwx/v3/jwa"
1518)
1619
@@ -119,20 +122,113 @@ func init() {
119122 }
120123 {
121124 f := KeyImportFunc (okpPrivateKeyToJWK )
122- for _ , k := range []interface {}{ed25519 .PrivateKey (nil ), ecdh.PrivateKey {}, & ecdh.PrivateKey {}} {
125+ for _ , k := range []interface {}{ed25519 .PrivateKey (nil )} {
126+ RegisterKeyImporter (k , f )
127+ }
128+ }
129+ {
130+ f := KeyImportFunc (ecdhPrivateKeyToJWK )
131+ for _ , k := range []interface {}{ecdh.PrivateKey {}, & ecdh.PrivateKey {}} {
123132 RegisterKeyImporter (k , f )
124133 }
125134 }
126135 {
127136 f := KeyImportFunc (okpPublicKeyToJWK )
128- for _ , k := range []interface {}{ed25519 .PublicKey (nil ), ecdh.PublicKey {}, & ecdh.PublicKey {}} {
137+ for _ , k := range []interface {}{ed25519 .PublicKey (nil )} {
138+ RegisterKeyImporter (k , f )
139+ }
140+ }
141+ {
142+ f := KeyImportFunc (ecdhPublicKeyToJWK )
143+ for _ , k := range []interface {}{ecdh.PublicKey {}, & ecdh.PublicKey {}} {
129144 RegisterKeyImporter (k , f )
130145 }
131146 }
132-
133147 RegisterKeyImporter ([]byte (nil ), KeyImportFunc (bytesToKey ))
134148}
135149
150+ func ecdhPrivateKeyToJWK (src interface {}) (Key , error ) {
151+ var raw * ecdh.PrivateKey
152+ switch src := src .(type ) {
153+ case * ecdh.PrivateKey :
154+ raw = src
155+ case ecdh.PrivateKey :
156+ raw = & src
157+ default :
158+ return nil , fmt .Errorf (`cannot convert key type '%T' to ECDH jwk.Key` , src )
159+ }
160+
161+ switch raw .Curve () {
162+ case ecdh .X25519 ():
163+ return okpPrivateKeyToJWK (raw )
164+ case ecdh .P256 ():
165+ return ecdhPrivateKeyToECJWK (raw , elliptic .P256 ())
166+ case ecdh .P384 ():
167+ return ecdhPrivateKeyToECJWK (raw , elliptic .P384 ())
168+ case ecdh .P521 ():
169+ return ecdhPrivateKeyToECJWK (raw , elliptic .P521 ())
170+ default :
171+ return nil , fmt .Errorf (`unsupported curve %s` , raw .Curve ())
172+ }
173+ }
174+
175+ func ecdhPrivateKeyToECJWK (raw * ecdh.PrivateKey , crv elliptic.Curve ) (Key , error ) {
176+ pub := raw .PublicKey ()
177+ rawpub := pub .Bytes ()
178+
179+ size := ecutil .CalculateKeySize (crv )
180+ var x , y , d big.Int
181+ x .SetBytes (rawpub [1 : 1 + size ])
182+ y .SetBytes (rawpub [1 + size :])
183+ d .SetBytes (raw .Bytes ())
184+
185+ var ecdsaPriv ecdsa.PrivateKey
186+ ecdsaPriv .Curve = crv
187+ ecdsaPriv .D = & d
188+ ecdsaPriv .X = & x
189+ ecdsaPriv .Y = & y
190+ return ecdsaPrivateKeyToJWK (& ecdsaPriv )
191+ }
192+
193+ func ecdhPublicKeyToJWK (src interface {}) (Key , error ) {
194+ var raw * ecdh.PublicKey
195+ switch src := src .(type ) {
196+ case * ecdh.PublicKey :
197+ raw = src
198+ case ecdh.PublicKey :
199+ raw = & src
200+ default :
201+ return nil , fmt .Errorf (`cannot convert key type '%T' to ECDH jwk.Key` , src )
202+ }
203+
204+ switch raw .Curve () {
205+ case ecdh .X25519 ():
206+ return okpPublicKeyToJWK (raw )
207+ case ecdh .P256 ():
208+ return ecdhPublicKeyToECJWK (raw , elliptic .P256 ())
209+ case ecdh .P384 ():
210+ return ecdhPublicKeyToECJWK (raw , elliptic .P384 ())
211+ case ecdh .P521 ():
212+ return ecdhPublicKeyToECJWK (raw , elliptic .P521 ())
213+ default :
214+ return nil , fmt .Errorf (`unsupported curve %s` , raw .Curve ())
215+ }
216+ }
217+
218+ func ecdhPublicKeyToECJWK (raw * ecdh.PublicKey , crv elliptic.Curve ) (Key , error ) {
219+ rawbytes := raw .Bytes ()
220+ size := ecutil .CalculateKeySize (crv )
221+ var x , y big.Int
222+
223+ x .SetBytes (rawbytes [1 : 1 + size ])
224+ y .SetBytes (rawbytes [1 + size :])
225+ var ecdsaPriv ecdsa.PublicKey
226+ ecdsaPriv .Curve = crv
227+ ecdsaPriv .X = & x
228+ ecdsaPriv .Y = & y
229+ return ecdsaPublicKeyToJWK (& ecdsaPriv )
230+ }
231+
136232// These may seem a bit repetitive and redandunt, but the problem is that
137233// each key type has its own Import method -- for example, Import(*ecdsa.PrivateKey)
138234// vs Import(*rsa.PrivateKey), and therefore they can't just be bundled into
@@ -277,21 +373,21 @@ func Export(key Key, dst interface{}) error {
277373 muKeyExporters .RLock ()
278374 exporters , ok := keyExporters [key .KeyType ()]
279375 muKeyExporters .RUnlock ()
280- if ok {
281- for _ , conv := range exporters {
282- v , err := conv .Export (key , dst )
283- if err != nil {
284- if errors .Is (err , ContinueError ()) {
285- continue
286- }
287- return fmt .Errorf (`jwk.Export: failed to export jwk.Key to raw format: %w` , err )
288- }
289-
290- if err := blackmagic .AssignIfCompatible (dst , v ); err != nil {
291- return fmt .Errorf (`jwk.Export: failed to assign key: %w` , err )
376+ if ! ok {
377+ return fmt .Errorf (`jwk.Export: no exporters registered for key type '%T'` , key )
378+ }
379+ for _ , conv := range exporters {
380+ v , err := conv .Export (key , dst )
381+ if err != nil {
382+ if errors .Is (err , ContinueError ()) {
383+ continue
292384 }
293- return nil
385+ return fmt .Errorf (`jwk.Export: failed to export jwk.Key to raw format: %w` , err )
386+ }
387+ if err := blackmagic .AssignIfCompatible (dst , v ); err != nil {
388+ return fmt .Errorf (`jwk.Export: failed to assign key: %w` , err )
294389 }
390+ return nil
295391 }
296- return fmt .Errorf (`jwk.Export: failed to find exporter for key type '%T'` , key )
392+ return fmt .Errorf (`jwk.Export: no suitable exporter found for key type '%T'` , key )
297393}
0 commit comments