lestrrat-go / jwx

Implementation of various JWx (Javascript Object Signing and Encryption/JOSE) technologies

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

jws.Sign() allows jwa.RS256 alg when using ECDSA key

eest opened this issue · comments

Describe the bug

I noticed that jws.Sign() does not appear to get upset if passed a jws.WithKey(jwa.RS256, jwsSigningKey) where jwsSigningKey contains a *ecdsa.PrivateKey

$ go version
go version go1.21.3 darwin/arm64

To Reproduce / Expected behavior

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"fmt"
	"log"

	"github.com/lestrrat-go/jwx/v2/jwa"
	"github.com/lestrrat-go/jwx/v2/jws"
)

func main() {
	jwsSigningKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatal(err)
	}

	signedMessage, err := jws.Sign([]byte("test message"), jws.WithKey(jwa.RS256, jwsSigningKey))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(signedMessage))

	verifiedContent, err := jws.Verify(signedMessage, jws.WithKey(jwa.ES256, &jwsSigningKey.PublicKey))
	if err != nil {
		log.Fatalf("failed to verify message: %s", err)
	}

	fmt.Printf("verified content: %s\n", string(verifiedContent))
}

Running it:

go run .
eyJhbGciOiJSUzI1NiJ9.dGVzdCBtZXNzYWdl.MEYCIQDGAqlqYaAvfoxgzfvazNqcVhy-1EmKpTtAYrWNdSkWUwIhAOKi3NADH2_hNccbq8PaIE4YdoAUyanoPbe3d3tSmgpe
2023/10/17 23:08:45 failed to verify message: could not verify message using any of the signatures or keys
exit status 1

While Verify() fails it surprises me that Sign() did not return an error when mixing an RSA-based alg with an ECDSA key. Is this expected?

If I change jwa.RS256 to jwa.ES256 like so:

signedMessage, err := jws.Sign([]byte(message), jws.WithKey(jwa.ES256, jwsSigningKey))

... then Verify() is also happy as expected:

go run .
eyJhbGciOiJFUzI1NiJ9.dGVzdCBtZXNzYWdl.0_PZhDXilhhVHp1FKZTPDrLry3dAXuP_DYlt9N0TOhJSeIp6j2yUgCbkN_yiK7-gs1zsPyT1v_sHHGX-E84LrQ
verified content: test message

Oh, hmmmmmmmm. This one's a bit tricky...
See, we allow crypto.Signer to be passed as key, so that hardware based keys and KMSes can do their thing.
The problem here is that jwk.ECDSA(Private|Public)Key is also a crypto.Signer.

let me think about it

After some digging around, I've concluded that I can protect users from misusing KNOWN key types (i.e. those that are defined in Go std lib and within this package, but not for other key types that implement crypto.Signer. I added some notes in the jws.WithKey documentation as well.

Please check #997 and let me know

Forgot to mention: @eest (just making sure...)

That was some impressive response time :)

I updated my go.mod in order to test your fix

require github.com/lestrrat-go/jwx/v2 gh-996

And now:

go run .
2023/10/18 09:04:00 failed to generate signature for signer #0 (alg=RS256): failed to sign payload: cannot use key of type *ecdsa.PrivateKey to generate RSA based signatures
exit status 1

So it looks good to me, thanks!

@eest merged. Please note that I'm going to wait releasing it for a bit. Please point our go.mod to the commit SHA for the time being, until we make a release.

Great! Even running on a currently released version is good enough for me right now, this was more of an unexpected behaviour when testing what happens when doing things wrong. I'll attempt to do things right instead :)