github.com/lestrrat-go/jwx/v2@v2.0.21/jws/jws_test.go (about)

     1  package jws_test
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"crypto"
     8  	"crypto/ecdsa"
     9  	"crypto/ed25519"
    10  	"crypto/rsa"
    11  	"crypto/sha256"
    12  	"crypto/sha512"
    13  	"encoding/asn1"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"math/big"
    18  	"net/http"
    19  	"net/http/httptest"
    20  	"os"
    21  	"sort"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/lestrrat-go/httprc"
    27  	"github.com/lestrrat-go/jwx/v2/internal/base64"
    28  	"github.com/lestrrat-go/jwx/v2/internal/json"
    29  	"github.com/lestrrat-go/jwx/v2/internal/jwxtest"
    30  	"github.com/lestrrat-go/jwx/v2/jwa"
    31  	"github.com/lestrrat-go/jwx/v2/jwk"
    32  	"github.com/lestrrat-go/jwx/v2/jws"
    33  	"github.com/lestrrat-go/jwx/v2/jwt"
    34  	"github.com/lestrrat-go/jwx/v2/x25519"
    35  	"github.com/stretchr/testify/assert"
    36  	"github.com/stretchr/testify/require"
    37  )
    38  
    39  const examplePayload = `{"iss":"joe",` + "\r\n" + ` "exp":1300819380,` + "\r\n" + ` "http://example.com/is_root":true}`
    40  const exampleCompactSerialization = `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk`
    41  const badValue = "%badvalue%"
    42  
    43  var hasES256K bool
    44  
    45  func TestSanity(t *testing.T) {
    46  	t.Run("sanity: Verify with single key", func(t *testing.T) {
    47  		key, err := jwk.ParseKey([]byte(`{
    48      "kty": "oct",
    49      "k": "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
    50    }`))
    51  		require.NoError(t, err, `jwk.ParseKey should succeed`)
    52  		payload, err := jws.Verify([]byte(exampleCompactSerialization), jws.WithKey(jwa.HS256, key))
    53  		require.NoError(t, err, `jws.Verify should succeed`)
    54  		require.Equal(t, []byte(examplePayload), payload, `payloads should match`)
    55  	})
    56  }
    57  
    58  func TestParseReader(t *testing.T) {
    59  	t.Parallel()
    60  	t.Run("Empty []byte", func(t *testing.T) {
    61  		t.Parallel()
    62  		_, err := jws.Parse(nil)
    63  		require.Error(t, err, "Parsing an empty byte slice should result in an error")
    64  	})
    65  	t.Run("Empty bytes.Buffer", func(t *testing.T) {
    66  		t.Parallel()
    67  		_, err := jws.ParseReader(&bytes.Buffer{})
    68  		require.Error(t, err, "Parsing an empty buffer should result in an error")
    69  	})
    70  	t.Run("Compact detached payload", func(t *testing.T) {
    71  		t.Parallel()
    72  		split := strings.Split(exampleCompactSerialization, ".")
    73  		incoming := strings.Join([]string{split[0], "", split[2]}, ".")
    74  		_, err := jws.ParseString(incoming)
    75  		require.NoError(t, err, `jws.ParseString should succeed`)
    76  	})
    77  	t.Run("Compact missing header", func(t *testing.T) {
    78  		t.Parallel()
    79  		incoming := strings.Join(
    80  			(strings.Split(
    81  				exampleCompactSerialization,
    82  				".",
    83  			))[:2],
    84  			".",
    85  		)
    86  
    87  		for _, useReader := range []bool{true, false} {
    88  			var err error
    89  			if useReader {
    90  				// Force ParseReader() to choose un-optimized path by using bufio.NewReader
    91  				_, err = jws.ParseReader(bufio.NewReader(strings.NewReader(incoming)))
    92  			} else {
    93  				_, err = jws.ParseString(incoming)
    94  			}
    95  			require.Error(t, err, "Parsing compact serialization with less than 3 parts should be an error")
    96  		}
    97  	})
    98  	t.Run("Compact bad header", func(t *testing.T) {
    99  		t.Parallel()
   100  		parts := strings.Split(exampleCompactSerialization, ".")
   101  		parts[0] = badValue
   102  		incoming := strings.Join(parts, ".")
   103  
   104  		for _, useReader := range []bool{true, false} {
   105  			var err error
   106  			if useReader {
   107  				_, err = jws.ParseReader(bufio.NewReader(strings.NewReader(incoming)))
   108  			} else {
   109  				_, err = jws.ParseString(incoming)
   110  			}
   111  			require.Error(t, err, "Parsing compact serialization with bad header should be an error")
   112  		}
   113  	})
   114  	t.Run("Compact bad payload", func(t *testing.T) {
   115  		t.Parallel()
   116  		parts := strings.Split(exampleCompactSerialization, ".")
   117  		parts[1] = badValue
   118  		incoming := strings.Join(parts, ".")
   119  
   120  		for _, useReader := range []bool{true, false} {
   121  			var err error
   122  			if useReader {
   123  				_, err = jws.ParseReader(bufio.NewReader(strings.NewReader(incoming)))
   124  			} else {
   125  				_, err = jws.ParseString(incoming)
   126  			}
   127  			require.Error(t, err, "Parsing compact serialization with bad payload should be an error")
   128  		}
   129  	})
   130  	t.Run("Compact bad signature", func(t *testing.T) {
   131  		t.Parallel()
   132  		parts := strings.Split(exampleCompactSerialization, ".")
   133  		parts[2] = badValue
   134  		incoming := strings.Join(parts, ".")
   135  
   136  		for _, useReader := range []bool{true, false} {
   137  			var err error
   138  			if useReader {
   139  				_, err = jws.ParseReader(bufio.NewReader(strings.NewReader(incoming)))
   140  			} else {
   141  				_, err = jws.ParseString(incoming)
   142  			}
   143  			require.Error(t, err, "Parsing compact serialization with bad signature should be an error")
   144  		}
   145  	})
   146  }
   147  
   148  type dummyCryptoSigner struct {
   149  	raw crypto.Signer
   150  }
   151  
   152  func (s *dummyCryptoSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
   153  	return s.raw.Sign(rand, digest, opts)
   154  }
   155  
   156  func (s *dummyCryptoSigner) Public() crypto.PublicKey {
   157  	return s.raw.Public()
   158  }
   159  
   160  var _ crypto.Signer = &dummyCryptoSigner{}
   161  
   162  type dummyECDSACryptoSigner struct {
   163  	raw *ecdsa.PrivateKey
   164  }
   165  
   166  func (es *dummyECDSACryptoSigner) Public() crypto.PublicKey {
   167  	return es.raw.Public()
   168  }
   169  
   170  func (es *dummyECDSACryptoSigner) Sign(rand io.Reader, digest []byte, _ crypto.SignerOpts) ([]byte, error) {
   171  	// The implementation is the same as ecdsaCryptoSigner.
   172  	// This is just here to test the interface conversion
   173  	r, s, err := ecdsa.Sign(rand, es.raw, digest)
   174  	if err != nil {
   175  		return nil, fmt.Errorf(`failed to sign payload using ecdsa: %w`, err)
   176  	}
   177  
   178  	return asn1.Marshal(struct {
   179  		R *big.Int
   180  		S *big.Int
   181  	}{R: r, S: s})
   182  }
   183  
   184  var _ crypto.Signer = &dummyECDSACryptoSigner{}
   185  
   186  func testRoundtrip(t *testing.T, payload []byte, alg jwa.SignatureAlgorithm, signKey interface{}, keys map[string]interface{}) {
   187  	jwkKey, err := jwk.FromRaw(signKey)
   188  	require.NoError(t, err, `jwk.New should succeed`)
   189  	signKeys := []struct {
   190  		Name string
   191  		Key  interface{}
   192  	}{
   193  		{
   194  			Name: "Raw Key",
   195  			Key:  signKey,
   196  		},
   197  		{
   198  			Name: "JWK Key",
   199  			Key:  jwkKey,
   200  		},
   201  	}
   202  
   203  	if es, ok := signKey.(*ecdsa.PrivateKey); ok {
   204  		signKeys = append(signKeys, struct {
   205  			Name string
   206  			Key  interface{}
   207  		}{
   208  			Name: "crypto.Hash",
   209  			Key:  &dummyECDSACryptoSigner{raw: es},
   210  		})
   211  	} else if cs, ok := signKey.(crypto.Signer); ok {
   212  		signKeys = append(signKeys, struct {
   213  			Name string
   214  			Key  interface{}
   215  		}{
   216  			Name: "crypto.Hash",
   217  			Key:  &dummyCryptoSigner{raw: cs},
   218  		})
   219  	}
   220  
   221  	for _, key := range signKeys {
   222  		key := key
   223  		t.Run(key.Name, func(t *testing.T) {
   224  			signed, err := jws.Sign(payload, jws.WithKey(alg, key.Key))
   225  			require.NoError(t, err, "jws.Sign should succeed")
   226  
   227  			parsers := map[string]func([]byte) (*jws.Message, error){
   228  				"ParseReader(io.Reader)": func(b []byte) (*jws.Message, error) { return jws.ParseReader(bufio.NewReader(bytes.NewReader(b))) },
   229  				"Parse([]byte)":          func(b []byte) (*jws.Message, error) { return jws.Parse(b) },
   230  				"ParseString(string)":    func(b []byte) (*jws.Message, error) { return jws.ParseString(string(b)) },
   231  			}
   232  			for name, f := range parsers {
   233  				name := name
   234  				f := f
   235  				t.Run(name, func(t *testing.T) {
   236  					t.Parallel()
   237  					m, err := f(signed)
   238  					require.NoError(t, err, "(%s) %s is successful", alg, name)
   239  					require.Equal(t, payload, m.Payload(), "(%s) %s: Payload is decoded", alg, name)
   240  				})
   241  			}
   242  
   243  			for name, testKey := range keys {
   244  				name := name
   245  				testKey := testKey
   246  				t.Run(name, func(t *testing.T) {
   247  					verified, err := jws.Verify(signed, jws.WithKey(alg, testKey))
   248  					require.NoError(t, err, "(%s) Verify is successful", alg)
   249  					require.Equal(t, payload, verified, "(%s) Verified payload is the same", alg)
   250  				})
   251  			}
   252  		})
   253  	}
   254  }
   255  
   256  func TestRoundtrip(t *testing.T) {
   257  	t.Parallel()
   258  	payload := []byte("Lorem ipsum")
   259  
   260  	t.Run("HMAC", func(t *testing.T) {
   261  		t.Parallel()
   262  		sharedkey := []byte("Avracadabra")
   263  		jwkKey, _ := jwk.FromRaw(sharedkey)
   264  		keys := map[string]interface{}{
   265  			"[]byte":  sharedkey,
   266  			"jwk.Key": jwkKey,
   267  		}
   268  		hmacAlgorithms := []jwa.SignatureAlgorithm{jwa.HS256, jwa.HS384, jwa.HS512}
   269  		for _, alg := range hmacAlgorithms {
   270  			alg := alg
   271  			t.Run(alg.String(), func(t *testing.T) {
   272  				t.Parallel()
   273  				testRoundtrip(t, payload, alg, sharedkey, keys)
   274  			})
   275  		}
   276  	})
   277  	t.Run("ECDSA", func(t *testing.T) {
   278  		t.Parallel()
   279  		key, err := jwxtest.GenerateEcdsaKey(jwa.P521)
   280  		require.NoError(t, err, "ECDSA key generated")
   281  		jwkKey, _ := jwk.FromRaw(key.PublicKey)
   282  		keys := map[string]interface{}{
   283  			"Verify(ecdsa.PublicKey)":  key.PublicKey,
   284  			"Verify(*ecdsa.PublicKey)": &key.PublicKey,
   285  			"Verify(jwk.Key)":          jwkKey,
   286  		}
   287  		for _, alg := range []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512} {
   288  			alg := alg
   289  			t.Run(alg.String(), func(t *testing.T) {
   290  				t.Parallel()
   291  				testRoundtrip(t, payload, alg, key, keys)
   292  			})
   293  		}
   294  	})
   295  	t.Run("RSA", func(t *testing.T) {
   296  		t.Parallel()
   297  		key, err := jwxtest.GenerateRsaKey()
   298  		require.NoError(t, err, "RSA key generated")
   299  		jwkKey, _ := jwk.FromRaw(key.PublicKey)
   300  		keys := map[string]interface{}{
   301  			"Verify(rsa.PublicKey)":  key.PublicKey,
   302  			"Verify(*rsa.PublicKey)": &key.PublicKey,
   303  			"Verify(jwk.Key)":        jwkKey,
   304  		}
   305  		for _, alg := range []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512} {
   306  			alg := alg
   307  			t.Run(alg.String(), func(t *testing.T) {
   308  				t.Parallel()
   309  				testRoundtrip(t, payload, alg, key, keys)
   310  			})
   311  		}
   312  	})
   313  	t.Run("EdDSA", func(t *testing.T) {
   314  		t.Parallel()
   315  		key, err := jwxtest.GenerateEd25519Key()
   316  		require.NoError(t, err, "ed25519 key generated")
   317  		pubkey := key.Public()
   318  		jwkKey, _ := jwk.FromRaw(pubkey)
   319  		keys := map[string]interface{}{
   320  			"Verify(ed25519.Public())": pubkey,
   321  			// Meh, this doesn't work
   322  			// "Verify(*ed25519.Public())": &pubkey,
   323  			"Verify(jwk.Key)": jwkKey,
   324  		}
   325  		for _, alg := range []jwa.SignatureAlgorithm{jwa.EdDSA} {
   326  			alg := alg
   327  			t.Run(alg.String(), func(t *testing.T) {
   328  				t.Parallel()
   329  				testRoundtrip(t, payload, alg, key, keys)
   330  			})
   331  		}
   332  	})
   333  }
   334  
   335  func TestSignMulti2(t *testing.T) {
   336  	sharedkey := []byte("Avracadabra")
   337  	payload := []byte("Lorem ipsum")
   338  	hmacAlgorithms := []jwa.SignatureAlgorithm{jwa.HS256, jwa.HS384, jwa.HS512}
   339  	var signed []byte
   340  	t.Run("Sign", func(t *testing.T) {
   341  		var options = []jws.SignOption{jws.WithJSON()}
   342  		for _, alg := range hmacAlgorithms {
   343  			options = append(options, jws.WithKey(alg, sharedkey)) // (signer, sharedkey, nil, nil))
   344  		}
   345  		var err error
   346  		signed, err = jws.Sign(payload, options...)
   347  		require.NoError(t, err, `jws.SignMulti should succeed`)
   348  	})
   349  	for _, alg := range hmacAlgorithms {
   350  		alg := alg
   351  		t.Run("Verify "+alg.String(), func(t *testing.T) {
   352  			m := jws.NewMessage()
   353  			verified, err := jws.Verify(signed, jws.WithKey(alg, sharedkey), jws.WithMessage(m))
   354  			require.NoError(t, err, "Verify succeeded")
   355  			require.Equal(t, payload, verified, "verified payload matches")
   356  
   357  			// XXX This actally doesn't really test much, but if there was anything
   358  			// wrong, the process should have failed well before reaching here
   359  			require.Equal(t, payload, m.Payload(), "message payload matches")
   360  		})
   361  	}
   362  }
   363  
   364  func TestEncode(t *testing.T) {
   365  	t.Parallel()
   366  
   367  	// HS256Compact tests that https://tools.ietf.org/html/rfc7515#appendix-A.1 works
   368  	t.Run("HS256Compact", func(t *testing.T) {
   369  		t.Parallel()
   370  		const hdr = `{"typ":"JWT",` + "\r\n" + ` "alg":"HS256"}`
   371  		const hmacKey = `AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow`
   372  		const expected = `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk`
   373  
   374  		hmacKeyDecoded, err := base64.DecodeString(hmacKey)
   375  		require.NoError(t, err, "HMAC base64 decoded successful")
   376  
   377  		hdrbuf := base64.Encode([]byte(hdr))
   378  		payload := base64.Encode([]byte(examplePayload))
   379  
   380  		signingInput := bytes.Join(
   381  			[][]byte{
   382  				hdrbuf,
   383  				payload,
   384  			},
   385  			[]byte{'.'},
   386  		)
   387  
   388  		sign, err := jws.NewSigner(jwa.HS256)
   389  		require.NoError(t, err, "HMAC signer created successfully")
   390  
   391  		signature, err := sign.Sign(signingInput, hmacKeyDecoded)
   392  		require.NoError(t, err, "PayloadSign is successful")
   393  		sigbuf := base64.Encode(signature)
   394  
   395  		encoded := bytes.Join(
   396  			[][]byte{
   397  				signingInput,
   398  				sigbuf,
   399  			},
   400  			[]byte{'.'},
   401  		)
   402  		require.Equal(t, expected, string(encoded), "generated compact serialization should match")
   403  
   404  		msg, err := jws.ParseReader(bytes.NewReader(encoded))
   405  		require.NoError(t, err, "Parsing compact encoded serialization succeeds")
   406  
   407  		signatures := msg.Signatures()
   408  		require.Len(t, signatures, 1, `there should be exactly one signature`)
   409  
   410  		algorithm := signatures[0].ProtectedHeaders().Algorithm()
   411  		if algorithm != jwa.HS256 {
   412  			t.Fatal("Algorithm in header does not match")
   413  		}
   414  
   415  		v, err := jws.NewVerifier(jwa.HS256)
   416  		require.NoError(t, err, "HmacVerify created")
   417  
   418  		require.NoError(t, v.Verify(signingInput, signature, hmacKeyDecoded), "Verify succeeds")
   419  	})
   420  	t.Run("ES512Compact", func(t *testing.T) {
   421  		t.Parallel()
   422  		// ES256Compact tests that https://tools.ietf.org/html/rfc7515#appendix-A.3 works
   423  		hdr := []byte{123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 53, 49, 50, 34, 125}
   424  		const jwksrc = `{
   425  "kty":"EC",
   426  "crv":"P-521",
   427  "x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk",
   428  "y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2",
   429  "d":"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPAxerEzgdRhajnu0ferB0d53vM9mE15j2C"
   430  }`
   431  
   432  		// "Payload"
   433  		jwsPayload := []byte{80, 97, 121, 108, 111, 97, 100}
   434  
   435  		standardHeaders := jws.NewHeaders()
   436  		require.NoError(t, json.Unmarshal(hdr, standardHeaders), `parsing headers should succeed`)
   437  
   438  		alg := standardHeaders.Algorithm()
   439  
   440  		jwkKey, err := jwk.ParseKey([]byte(jwksrc))
   441  		if err != nil {
   442  			t.Fatal("Failed to parse JWK")
   443  		}
   444  		var key interface{}
   445  		require.NoError(t, jwkKey.Raw(&key), `jwk.Raw should succeed`)
   446  		var jwsCompact []byte
   447  		jwsCompact, err = jws.Sign(jwsPayload, jws.WithKey(alg, key))
   448  		if err != nil {
   449  			t.Fatal("Failed to sign message")
   450  		}
   451  
   452  		// Verify with standard ecdsa library
   453  		_, _, jwsSignature, err := jws.SplitCompact(jwsCompact)
   454  		if err != nil {
   455  			t.Fatal("Failed to split compact JWT")
   456  		}
   457  
   458  		decodedJwsSignature, err := base64.Decode(jwsSignature)
   459  		require.NoError(t, err, `base64.Decode should succeed`)
   460  		r, s := &big.Int{}, &big.Int{}
   461  		n := len(decodedJwsSignature) / 2
   462  		r.SetBytes(decodedJwsSignature[:n])
   463  		s.SetBytes(decodedJwsSignature[n:])
   464  		signingHdr := base64.Encode(hdr)
   465  		signingPayload := base64.Encode(jwsPayload)
   466  
   467  		jwsSigningInput := bytes.Join(
   468  			[][]byte{
   469  				signingHdr,
   470  				signingPayload,
   471  			},
   472  			[]byte{'.'},
   473  		)
   474  		hashed512 := sha512.Sum512(jwsSigningInput)
   475  		ecdsaPrivateKey := key.(*ecdsa.PrivateKey)
   476  		require.True(t, ecdsa.Verify(&ecdsaPrivateKey.PublicKey, hashed512[:], r, s), "ecdsa.Verify should succeed")
   477  
   478  		// Verify with API library
   479  		publicKey, err := jwk.PublicRawKeyOf(key)
   480  		require.NoError(t, err, `jwk.PublicRawKeyOf should succeed`)
   481  		verifiedPayload, err := jws.Verify(jwsCompact, jws.WithKey(alg, publicKey))
   482  		if err != nil || string(verifiedPayload) != string(jwsPayload) {
   483  			t.Fatal("Failed to verify message")
   484  		}
   485  	})
   486  	t.Run("RS256Compact", func(t *testing.T) {
   487  		t.Parallel()
   488  		// RS256Compact tests that https://tools.ietf.org/html/rfc7515#appendix-A.2 works
   489  		const hdr = `{"alg":"RS256"}`
   490  		const expected = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw`
   491  		const jwksrc = `{
   492      "kty":"RSA",
   493      "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
   494      "e":"AQAB",
   495      "d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ",
   496      "p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc",
   497      "q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc",
   498      "dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0",
   499      "dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
   500      "qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
   501    }`
   502  
   503  		privkey, err := jwk.ParseKey([]byte(jwksrc))
   504  		require.NoError(t, err, `parsing jwk should be successful`)
   505  
   506  		var rawkey rsa.PrivateKey
   507  		require.NoError(t, privkey.Raw(&rawkey), `obtaining raw key should succeed`)
   508  
   509  		sign, err := jws.NewSigner(jwa.RS256)
   510  		require.NoError(t, err, "RsaSign created successfully")
   511  
   512  		hdrbuf := base64.Encode([]byte(hdr))
   513  		payload := base64.Encode([]byte(examplePayload))
   514  		signingInput := bytes.Join(
   515  			[][]byte{
   516  				hdrbuf,
   517  				payload,
   518  			},
   519  			[]byte{'.'},
   520  		)
   521  		signature, err := sign.Sign(signingInput, rawkey)
   522  		require.NoError(t, err, "PayloadSign is successful")
   523  		sigbuf := base64.Encode(signature)
   524  
   525  		encoded := bytes.Join(
   526  			[][]byte{
   527  				signingInput,
   528  				sigbuf,
   529  			},
   530  			[]byte{'.'},
   531  		)
   532  
   533  		require.Equal(t, expected, string(encoded), "generated compact serialization should match")
   534  
   535  		msg, err := jws.ParseReader(bytes.NewReader(encoded))
   536  		require.NoError(t, err, "Parsing compact encoded serialization succeeds")
   537  
   538  		signatures := msg.Signatures()
   539  		require.Len(t, signatures, 1, `there should be exactly one signature`)
   540  
   541  		algorithm := signatures[0].ProtectedHeaders().Algorithm()
   542  		if algorithm != jwa.RS256 {
   543  			t.Fatal("Algorithm in header does not match")
   544  		}
   545  
   546  		v, err := jws.NewVerifier(jwa.RS256)
   547  		require.NoError(t, err, "Verify created")
   548  		require.NoError(t, v.Verify(signingInput, signature, rawkey.PublicKey), "Verify succeeds")
   549  	})
   550  	t.Run("ES256Compact", func(t *testing.T) {
   551  		t.Parallel()
   552  		// ES256Compact tests that https://tools.ietf.org/html/rfc7515#appendix-A.3 works
   553  		const hdr = `{"alg":"ES256"}`
   554  		const jwksrc = `{
   555      "kty":"EC",
   556      "crv":"P-256",
   557      "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
   558      "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
   559      "d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"
   560    }`
   561  		privkey, err := jwk.ParseKey([]byte(jwksrc))
   562  		require.NoError(t, err, `parsing jwk should succeed`)
   563  
   564  		var rawkey ecdsa.PrivateKey
   565  		require.NoError(t, privkey.Raw(&rawkey), `obtaining raw key should succeed`)
   566  
   567  		signer, err := jws.NewSigner(jwa.ES256)
   568  		require.NoError(t, err, "RsaSign created successfully")
   569  
   570  		hdrbuf := base64.Encode([]byte(hdr))
   571  		payload := base64.Encode([]byte(examplePayload))
   572  		signingInput := bytes.Join(
   573  			[][]byte{
   574  				hdrbuf,
   575  				payload,
   576  			},
   577  			[]byte{'.'},
   578  		)
   579  		signature, err := signer.Sign(signingInput, &rawkey)
   580  		require.NoError(t, err, "PayloadSign is successful")
   581  		sigbuf := base64.Encode(signature)
   582  		require.NoError(t, err, "base64 encode successful")
   583  
   584  		encoded := bytes.Join(
   585  			[][]byte{
   586  				signingInput,
   587  				sigbuf,
   588  			},
   589  			[]byte{'.'},
   590  		)
   591  
   592  		// The signature contains random factor, so unfortunately we can't match
   593  		// the output against a fixed expected outcome. We'll wave doing an
   594  		// exact match, and just try to verify using the signature
   595  
   596  		msg, err := jws.ParseReader(bytes.NewReader(encoded))
   597  		require.NoError(t, err, "Parsing compact encoded serialization succeeds")
   598  
   599  		signatures := msg.Signatures()
   600  		require.Len(t, signatures, 1, `there should be exactly one signature`)
   601  
   602  		algorithm := signatures[0].ProtectedHeaders().Algorithm()
   603  		if algorithm != jwa.ES256 {
   604  			t.Fatal("Algorithm in header does not match")
   605  		}
   606  
   607  		v, err := jws.NewVerifier(jwa.ES256)
   608  		require.NoError(t, err, "EcdsaVerify created")
   609  		require.NoError(t, v.Verify(signingInput, signature, rawkey.PublicKey), "Verify succeeds")
   610  	})
   611  	t.Run("EdDSACompact", func(t *testing.T) {
   612  		t.Parallel()
   613  		// EdDSACompact tests that https://tools.ietf.org/html/rfc8037#appendix-A.1-5 works
   614  		const hdr = `{"alg":"EdDSA"}`
   615  		const jwksrc = `{
   616      "kty":"OKP",
   617      "crv":"Ed25519",
   618      "d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
   619      "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
   620    }`
   621  		const examplePayload = `Example of Ed25519 signing`
   622  		const expected = `hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg`
   623  		expectedDecoded, err := base64.Decode([]byte(expected))
   624  		require.NoError(t, err, "Expected Signature decode successful")
   625  
   626  		privkey, err := jwk.ParseKey([]byte(jwksrc))
   627  		require.NoError(t, err, `parsing jwk should succeed`)
   628  
   629  		var rawkey ed25519.PrivateKey
   630  		require.NoError(t, privkey.Raw(&rawkey), `obtaining raw key should succeed`)
   631  
   632  		signer, err := jws.NewSigner(jwa.EdDSA)
   633  		require.NoError(t, err, "EdDSASign created successfully")
   634  
   635  		hdrbuf := base64.Encode([]byte(hdr))
   636  		payload := base64.Encode([]byte(examplePayload))
   637  		signingInput := bytes.Join(
   638  			[][]byte{
   639  				hdrbuf,
   640  				payload,
   641  			},
   642  			[]byte{'.'},
   643  		)
   644  
   645  		signature, err := signer.Sign(signingInput, rawkey)
   646  		require.NoError(t, err, "PayloadSign is successful")
   647  		sigbuf := base64.Encode(signature)
   648  		encoded := bytes.Join(
   649  			[][]byte{
   650  				signingInput,
   651  				sigbuf,
   652  			},
   653  			[]byte{'.'},
   654  		)
   655  
   656  		// The signature contains random factor, so unfortunately we can't match
   657  		// the output against a fixed expected outcome. We'll wave doing an
   658  		// exact match, and just try to verify using the signature
   659  
   660  		msg, err := jws.ParseReader(bytes.NewReader(encoded))
   661  		require.NoError(t, err, "Parsing compact encoded serialization succeeds")
   662  
   663  		signatures := msg.Signatures()
   664  		require.Len(t, signatures, 1, `there should be exactly one signature`)
   665  
   666  		algorithm := signatures[0].ProtectedHeaders().Algorithm()
   667  		if algorithm != jwa.EdDSA {
   668  			t.Fatal("Algorithm in header does not match")
   669  		}
   670  
   671  		v, err := jws.NewVerifier(jwa.EdDSA)
   672  		require.NoError(t, err, "EcdsaVerify created")
   673  		require.NoError(t, v.Verify(signingInput, signature, rawkey.Public()), "Verify succeeds")
   674  		require.Equal(t, signature, expectedDecoded, "signatures match")
   675  	})
   676  	t.Run("UnsecuredCompact", func(t *testing.T) {
   677  		t.Parallel()
   678  		s := `eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.`
   679  
   680  		m, err := jws.ParseReader(strings.NewReader(s))
   681  		require.NoError(t, err, "Parsing compact serialization")
   682  
   683  		{
   684  			v := map[string]interface{}{}
   685  			require.NoError(t, json.Unmarshal(m.Payload(), &v), "Unmarshal payload")
   686  			require.Equal(t, v["iss"], "joe", "iss matches")
   687  			require.Equal(t, int(v["exp"].(float64)), 1300819380, "exp matches")
   688  			require.Equal(t, v["http://example.com/is_root"], true, "'http://example.com/is_root' matches")
   689  		}
   690  
   691  		require.Len(t, m.Signatures(), 1, "There should be 1 signature")
   692  
   693  		signatures := m.Signatures()
   694  		algorithm := signatures[0].ProtectedHeaders().Algorithm()
   695  		if algorithm != jwa.NoSignature {
   696  			t.Fatal("Algorithm in header does not match")
   697  		}
   698  
   699  		require.Empty(t, signatures[0].Signature(), "Signature should be empty")
   700  	})
   701  	t.Run("CompleteJSON", func(t *testing.T) {
   702  		t.Parallel()
   703  		s := `{
   704      "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
   705      "signatures":[
   706        {
   707          "header": {"kid":"2010-12-29"},
   708          "protected":"eyJhbGciOiJSUzI1NiJ9",
   709          "signature": "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"
   710        },
   711        {
   712          "header": {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
   713          "protected":"eyJhbGciOiJFUzI1NiJ9",
   714          "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
   715        }
   716      ]
   717    }`
   718  
   719  		m, err := jws.ParseReader(strings.NewReader(s))
   720  		require.NoError(t, err, "Unmarshal complete json serialization")
   721  		require.Len(t, m.Signatures(), 2, "There should be 2 signatures")
   722  
   723  		sigs := m.LookupSignature("2010-12-29")
   724  		require.Len(t, sigs, 1, "There should be 1 signature with kid = '2010-12-29'")
   725  	})
   726  	t.Run("Protected Header lookup", func(t *testing.T) {
   727  		t.Parallel()
   728  		s := `{
   729      "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
   730      "signatures":[
   731        {
   732          "header": {"cty":"example"},
   733          "protected":"eyJhbGciOiJFUzI1NiIsImtpZCI6ImU5YmMwOTdhLWNlNTEtNDAzNi05NTYyLWQyYWRlODgyZGIwZCJ9",
   734          "signature": "JcLb1udPAV72TayGv6eawZKlIQQ3K1NzB0fU7wwYoFypGxEczdCQU-V9jp4WwY2ueJKYeE4fF6jigB0PdSKR0Q"
   735        }
   736      ]
   737    }`
   738  
   739  		// Protected Header is {"alg":"ES256","kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}
   740  		// This protected header combination forces the parser/unmarshal to go trough the code path to populate and look for protected header fields.
   741  		// The signature is valid.
   742  
   743  		m, err := jws.ParseReader(strings.NewReader(s))
   744  		require.NoError(t, err, "Unmarshal complete json serialization")
   745  		require.Len(t, m.Signatures(), 1, "There should be 1 signature")
   746  
   747  		sigs := m.LookupSignature("e9bc097a-ce51-4036-9562-d2ade882db0d")
   748  		require.Len(t, sigs, 1, "There should be 1 signature with kid = '2010-12-29'")
   749  	})
   750  	t.Run("FlattenedJSON", func(t *testing.T) {
   751  		t.Parallel()
   752  		s := `{
   753      "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
   754      "protected":"eyJhbGciOiJFUzI1NiJ9",
   755      "header": {
   756        "kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"
   757      },
   758      "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
   759    }`
   760  
   761  		m, err := jws.ParseReader(strings.NewReader(s))
   762  		require.NoError(t, err, "Parsing flattened json serialization")
   763  		require.Len(t, m.Signatures(), 1, "There should be 1 signature")
   764  
   765  		jsonbuf, _ := json.MarshalIndent(m, "", "  ")
   766  		t.Logf("%s", jsonbuf)
   767  	})
   768  	t.Run("SplitCompact", func(t *testing.T) {
   769  		testcases := []struct {
   770  			Name string
   771  			Size int
   772  		}{
   773  			{Name: "Short", Size: 100},
   774  			{Name: "Long", Size: 8000},
   775  		}
   776  		for _, tc := range testcases {
   777  			size := tc.Size
   778  			t.Run(tc.Name, func(t *testing.T) {
   779  				t.Parallel()
   780  				// Create payload with X.Y.Z
   781  				var payload []byte
   782  				for i := 0; i < size; i++ {
   783  					payload = append(payload, 'X')
   784  				}
   785  				payload = append(payload, '.')
   786  				for i := 0; i < size; i++ {
   787  					payload = append(payload, 'Y')
   788  				}
   789  				payload = append(payload, '.')
   790  
   791  				for i := 0; i < size; i++ {
   792  					payload = append(payload, 'Y')
   793  				}
   794  
   795  				// Test using bytes, reader optimized and non-optimized path
   796  				for _, method := range []int{0, 1, 2} {
   797  					var x, y, z []byte
   798  					var err error
   799  					switch method {
   800  					case 0: // bytes
   801  						x, y, z, err = jws.SplitCompact(payload)
   802  					case 1: // un-optimized io.Reader
   803  						x, y, z, err = jws.SplitCompactReader(bytes.NewReader(payload))
   804  					default: // optimized io.Reader
   805  						x, y, z, err = jws.SplitCompactReader(bufio.NewReader(bytes.NewReader(payload)))
   806  					}
   807  					require.NoError(t, err, "SplitCompact should succeed")
   808  					require.Len(t, x, size, "Length of header")
   809  					require.Len(t, y, size, "Length of payload")
   810  					require.Len(t, z, size, "Length of signature")
   811  				}
   812  			})
   813  		}
   814  	})
   815  }
   816  
   817  func TestPublicHeaders(t *testing.T) {
   818  	key, err := jwxtest.GenerateRsaKey()
   819  	require.NoError(t, err, "GenerateKey should succeed")
   820  
   821  	signer, err := jws.NewSigner(jwa.RS256)
   822  	require.NoError(t, err, "jws.NewSigner should succeed")
   823  	_ = signer // TODO
   824  
   825  	pubkey := key.PublicKey
   826  	pubjwk, err := jwk.FromRaw(&pubkey)
   827  	require.NoError(t, err, "NewRsaPublicKey should succeed")
   828  	_ = pubjwk // TODO
   829  }
   830  
   831  func TestDecode_ES384Compact_NoSigTrim(t *testing.T) {
   832  	incoming := "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCIsImtpZCI6IjE5MzFmZTQ0YmFhMWNhZTkyZWUzNzYzOTQ0MDU1OGMwODdlMTRlNjk5ZWU5NjVhM2Q1OGU1MmU2NGY4MDE0NWIifQ.eyJpc3MiOiJicmt0LWNsaS0xLjAuN3ByZTEiLCJpYXQiOjE0ODQ2OTU1MjAsImp0aSI6IjgxYjczY2Y3In0.DdFi0KmPHSv4PfIMGcWGMSRLmZsfRPQ3muLFW6Ly2HpiLFFQWZ0VEanyrFV263wjlp3udfedgw_vrBLz3XC8CkbvCo_xeHMzaTr_yfhjoheSj8gWRLwB-22rOnUX_M0A"
   833  	t.Logf("incoming = '%s'", incoming)
   834  	const jwksrc = `{
   835      "kty":"EC",
   836      "crv":"P-384",
   837      "x":"YHVZ4gc1RDoqxKm4NzaN_Y1r7R7h3RM3JMteC478apSKUiLVb4UNytqWaLoE6ygH",
   838      "y":"CRKSqP-aYTIsqJfg_wZEEYUayUR5JhZaS2m4NLk2t1DfXZgfApAJ2lBO0vWKnUMp"
   839    }`
   840  
   841  	pubkey, err := jwk.ParseKey([]byte(jwksrc))
   842  	require.NoError(t, err, `parsing jwk should be successful`)
   843  
   844  	var rawkey ecdsa.PublicKey
   845  	require.NoError(t, pubkey.Raw(&rawkey), `obtaining raw key should succeed`)
   846  
   847  	v, err := jws.NewVerifier(jwa.ES384)
   848  	require.NoError(t, err, "EcdsaVerify created")
   849  
   850  	protected, payload, signature, err := jws.SplitCompact([]byte(incoming))
   851  	require.NoError(t, err, `jws.SplitCompact should succeed`)
   852  
   853  	var buf bytes.Buffer
   854  	buf.Write(protected)
   855  	buf.WriteByte('.')
   856  	buf.Write(payload)
   857  
   858  	decodedSignature, err := base64.Decode(signature)
   859  	require.NoError(t, err, `decoding signature should succeed`)
   860  	require.NoError(t, v.Verify(buf.Bytes(), decodedSignature, rawkey), "Verify succeeds")
   861  }
   862  
   863  func TestReadFile(t *testing.T) {
   864  	t.Parallel()
   865  
   866  	f, err := os.CreateTemp("", "test-read-file-*.jws")
   867  	require.NoError(t, err, `io.CreateTemp should succeed`)
   868  	defer f.Close()
   869  
   870  	fmt.Fprintf(f, "%s", exampleCompactSerialization)
   871  
   872  	if _, err := jws.ReadFile(f.Name()); !assert.NoError(t, err, `jws.ReadFile should succeed`) {
   873  		return
   874  	}
   875  }
   876  
   877  func TestVerifyNonUniqueKid(t *testing.T) {
   878  	const payload = "Lorem ipsum"
   879  	const kid = "notUniqueKid"
   880  	privateKey, err := jwxtest.GenerateRsaJwk()
   881  	require.NoError(t, err, "jwxtest.GenerateJwk should succeed")
   882  	_ = privateKey.Set(jwk.KeyIDKey, kid)
   883  	signed, err := jws.Sign([]byte(payload), jws.WithKey(jwa.RS256, privateKey))
   884  	require.NoError(t, err, `jws.Sign should succeed`)
   885  	correctKey, _ := jwk.PublicKeyOf(privateKey)
   886  	_ = correctKey.Set(jwk.AlgorithmKey, jwa.RS256)
   887  
   888  	makeSet := func(keys ...jwk.Key) jwk.Set {
   889  		set := jwk.NewSet()
   890  		for _, key := range keys {
   891  			_ = set.AddKey(key)
   892  		}
   893  		return set
   894  	}
   895  
   896  	testcases := []struct {
   897  		Name string
   898  		Key  func() jwk.Key // Generates the "wrong" key
   899  	}{
   900  		{
   901  			Name: `match 2 keys via same "kid"`,
   902  			Key: func() jwk.Key {
   903  				privateKey, _ := jwxtest.GenerateRsaJwk()
   904  				wrongKey, _ := jwk.PublicKeyOf(privateKey)
   905  				_ = wrongKey.Set(jwk.KeyIDKey, kid)
   906  				_ = wrongKey.Set(jwk.AlgorithmKey, jwa.RS256)
   907  				return wrongKey
   908  			},
   909  		},
   910  		{
   911  			Name: `match 2 keys via same "kid", same key value but different alg`,
   912  			Key: func() jwk.Key {
   913  				wrongKey, _ := correctKey.Clone()
   914  				_ = wrongKey.Set(jwk.KeyIDKey, kid)
   915  				_ = wrongKey.Set(jwk.AlgorithmKey, jwa.RS512)
   916  				return wrongKey
   917  			},
   918  		},
   919  		{
   920  			Name: `match 2 keys via same "kid", same key type but different alg`,
   921  			Key: func() jwk.Key {
   922  				privateKey, _ := jwxtest.GenerateRsaJwk()
   923  				wrongKey, _ := jwk.PublicKeyOf(privateKey)
   924  				_ = wrongKey.Set(jwk.KeyIDKey, kid)
   925  				_ = wrongKey.Set(jwk.AlgorithmKey, jwa.RS512)
   926  				return wrongKey
   927  			},
   928  		},
   929  		{
   930  			Name: `match 2 keys via same "kid" and different key type / alg`,
   931  			Key: func() jwk.Key {
   932  				privateKey, _ := jwxtest.GenerateEcdsaKey(jwa.P256)
   933  				wrongKey, err := jwk.PublicKeyOf(privateKey)
   934  				require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
   935  				_ = wrongKey.Set(jwk.KeyIDKey, kid)
   936  				_ = wrongKey.Set(jwk.AlgorithmKey, jwa.ES256K)
   937  				return wrongKey
   938  			},
   939  		},
   940  	}
   941  
   942  	for _, tc := range testcases {
   943  		tc := tc
   944  		wrongKey, err := tc.Key().Clone()
   945  		require.NoError(t, err, `cloning wrong key should succeed`)
   946  		for _, set := range []jwk.Set{makeSet(wrongKey, correctKey), makeSet(correctKey, wrongKey)} {
   947  			set := set
   948  			t.Run(tc.Name, func(t *testing.T) {
   949  				// Try matching in different orders
   950  				var usedKey jwk.Key
   951  				_, err = jws.Verify(signed, jws.WithKeySet(set, jws.WithMultipleKeysPerKeyID(true)), jws.WithKeyUsed(&usedKey))
   952  				require.NoError(t, err, `jws.Verify should succeed`)
   953  				require.Equal(t, usedKey, correctKey)
   954  			})
   955  		}
   956  	}
   957  }
   958  
   959  func TestVerifySet(t *testing.T) {
   960  	t.Parallel()
   961  	const payload = "Lorem ipsum"
   962  
   963  	makeSet := func(privkey jwk.Key) jwk.Set {
   964  		set := jwk.NewSet()
   965  		k1, _ := jwk.FromRaw([]byte("abracadabra"))
   966  		set.AddKey(k1)
   967  		k2, _ := jwk.FromRaw([]byte("opensesame"))
   968  		set.AddKey(k2)
   969  		pubkey, _ := jwk.PublicKeyOf(privkey)
   970  		pubkey.Set(jwk.AlgorithmKey, jwa.RS256)
   971  		set.AddKey(pubkey)
   972  		return set
   973  	}
   974  
   975  	for _, useJSON := range []bool{true, false} {
   976  		useJSON := useJSON
   977  		t.Run(fmt.Sprintf("useJSON=%t", useJSON), func(t *testing.T) {
   978  			t.Parallel()
   979  			t.Run(`match via "alg"`, func(t *testing.T) {
   980  				t.Parallel()
   981  				key, err := jwxtest.GenerateRsaJwk()
   982  				require.NoError(t, err, "jwxtest.GenerateJwk should succeed")
   983  
   984  				set := makeSet(key)
   985  				signed, err := jws.Sign([]byte(payload), jws.WithKey(jwa.RS256, key))
   986  				require.NoError(t, err, `jws.Sign should succeed`)
   987  				if useJSON {
   988  					m, err := jws.Parse(signed)
   989  					require.NoError(t, err, `jws.Parse should succeed`)
   990  					signed, err = json.Marshal(m)
   991  					require.NoError(t, err, `json.Marshal should succeed`)
   992  				}
   993  
   994  				var used jwk.Key
   995  				verified, err := jws.Verify(signed, jws.WithKeySet(set, jws.WithRequireKid(false)), jws.WithKeyUsed(&used))
   996  				require.NoError(t, err, `jws.Verify should succeed`)
   997  				require.Equal(t, []byte(payload), verified, `payload should match`)
   998  				expected, _ := jwk.PublicKeyOf(key)
   999  				thumb1, _ := expected.Thumbprint(crypto.SHA1)
  1000  				thumb2, _ := used.Thumbprint(crypto.SHA1)
  1001  				require.Equal(t, thumb1, thumb2, `keys should match`)
  1002  			})
  1003  			t.Run(`match via "kid"`, func(t *testing.T) {
  1004  				t.Parallel()
  1005  
  1006  				key, err := jwxtest.GenerateRsaJwk()
  1007  				require.NoError(t, err, "jwxtest.GenerateJwk should succeed")
  1008  				key.Set(jwk.KeyIDKey, `mykey`)
  1009  
  1010  				set := makeSet(key)
  1011  				signed, err := jws.Sign([]byte(payload), jws.WithKey(jwa.RS256, key))
  1012  				require.NoError(t, err, `jws.Sign should succeed`)
  1013  				if useJSON {
  1014  					m, err := jws.Parse(signed)
  1015  					require.NoError(t, err, `jws.Parse should succeed`)
  1016  					signed, err = json.Marshal(m)
  1017  					require.NoError(t, err, `json.Marshal should succeed`)
  1018  				}
  1019  
  1020  				var used jwk.Key
  1021  				verified, err := jws.Verify(signed, jws.WithKeySet(set), jws.WithKeyUsed(&used))
  1022  				require.NoError(t, err, `jws.Verify should succeed`)
  1023  				require.Equal(t, []byte(payload), verified, `payload should match`)
  1024  				expected, _ := jwk.PublicKeyOf(key)
  1025  				thumb1, _ := expected.Thumbprint(crypto.SHA1)
  1026  				thumb2, _ := used.Thumbprint(crypto.SHA1)
  1027  				require.Equal(t, thumb1, thumb2, `keys should match`)
  1028  			})
  1029  		})
  1030  	}
  1031  }
  1032  
  1033  func TestCustomField(t *testing.T) {
  1034  	// XXX has global effect!!!
  1035  	jws.RegisterCustomField(`x-birthday`, time.Time{})
  1036  	defer jws.RegisterCustomField(`x-birthday`, nil)
  1037  
  1038  	expected := time.Date(2015, 11, 4, 5, 12, 52, 0, time.UTC)
  1039  	bdaybytes, _ := expected.MarshalText() // RFC3339
  1040  
  1041  	payload := "Hello, World!"
  1042  	privkey, err := jwxtest.GenerateRsaJwk()
  1043  	require.NoError(t, err, `jwxtest.GenerateRsaJwk() should succeed`)
  1044  
  1045  	hdrs := jws.NewHeaders()
  1046  	hdrs.Set(`x-birthday`, string(bdaybytes))
  1047  
  1048  	signed, err := jws.Sign([]byte(payload), jws.WithKey(jwa.RS256, privkey, jws.WithProtectedHeaders(hdrs)))
  1049  	require.NoError(t, err, `jws.Sign should succeed`)
  1050  
  1051  	t.Run("jws.Parse + json.Unmarshal", func(t *testing.T) {
  1052  		msg, err := jws.Parse(signed)
  1053  		require.NoError(t, err, `jws.Parse should succeed`)
  1054  
  1055  		v, ok := msg.Signatures()[0].ProtectedHeaders().Get(`x-birthday`)
  1056  		require.True(t, ok, `msg.Signatures()[0].ProtectedHeaders().Get("x-birthday") should succeed`)
  1057  		require.Equal(t, expected, v, `values should match`)
  1058  
  1059  		// Create JSON from jws.Message
  1060  		buf, err := json.Marshal(msg)
  1061  		require.NoError(t, err, `json.Marshal should succeed`)
  1062  
  1063  		var msg2 jws.Message
  1064  		require.NoError(t, json.Unmarshal(buf, &msg2), `json.Unmarshal should succeed`)
  1065  
  1066  		v, ok = msg2.Signatures()[0].ProtectedHeaders().Get(`x-birthday`)
  1067  		require.True(t, ok, `msg2.Signatures()[0].ProtectedHeaders().Get("x-birthday") should succeed`)
  1068  		require.Equal(t, expected, v, `values should match`)
  1069  	})
  1070  }
  1071  
  1072  func TestWithMessage(t *testing.T) {
  1073  	key, err := jwxtest.GenerateRsaKey()
  1074  	require.NoError(t, err, "jwxtest.Generate should succeed")
  1075  
  1076  	const text = "hello, world"
  1077  	signed, err := jws.Sign([]byte(text), jws.WithKey(jwa.RS256, key))
  1078  	require.NoError(t, err, `jws.Sign should succeed`)
  1079  
  1080  	m := jws.NewMessage()
  1081  	payload, err := jws.Verify(signed, jws.WithKey(jwa.RS256, key.PublicKey), jws.WithMessage(m))
  1082  	require.NoError(t, err, `jws.Verify should succeed`)
  1083  	require.Equal(t, payload, []byte(text), `jws.Verify should produce the correct payload`)
  1084  
  1085  	parsed, err := jws.Parse(signed)
  1086  	require.NoError(t, err, `jws.Parse should succeed`)
  1087  
  1088  	// The result of using jws.WithMessage should match the result of jws.Parse
  1089  	buf1, _ := json.Marshal(m)
  1090  	buf2, _ := json.Marshal(parsed)
  1091  
  1092  	require.Equal(t, buf1, buf2, `result of jws.PArse and jws.Verify(..., jws.WithMessage()) should match`)
  1093  }
  1094  
  1095  func TestRFC7797(t *testing.T) {
  1096  	const keysrc = `{"kty":"oct",
  1097        "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
  1098       }`
  1099  
  1100  	key, err := jwk.ParseKey([]byte(keysrc))
  1101  	require.NoError(t, err, `jwk.Parse should succeed`)
  1102  
  1103  	t.Run("Invalid payload when b64 = false and NOT detached", func(t *testing.T) {
  1104  		const payload = `$.02`
  1105  		hdrs := jws.NewHeaders()
  1106  		hdrs.Set("b64", false)
  1107  		hdrs.Set("crit", "b64")
  1108  
  1109  		_, err := jws.Sign([]byte(payload), jws.WithKey(jwa.HS256, key, jws.WithProtectedHeaders(hdrs)))
  1110  		require.Error(t, err, `jws.Sign should fail`)
  1111  	})
  1112  	t.Run("Invalid usage when b64 = false and NOT detached", func(t *testing.T) {
  1113  		const payload = `$.02`
  1114  		hdrs := jws.NewHeaders()
  1115  		hdrs.Set("b64", false)
  1116  		hdrs.Set("crit", "b64")
  1117  
  1118  		_, err := jws.Sign([]byte(payload), jws.WithKey(jwa.HS256, key, jws.WithProtectedHeaders(hdrs)), jws.WithDetachedPayload([]byte(payload)))
  1119  		require.Error(t, err, `jws.Sign should fail`)
  1120  	})
  1121  	t.Run("Valid payload when b64 = false", func(t *testing.T) {
  1122  		testcases := []struct {
  1123  			Name     string
  1124  			Payload  []byte
  1125  			Detached bool
  1126  		}{
  1127  			{
  1128  				Name:     `(Detached) payload contains a period`,
  1129  				Payload:  []byte(`$.02`),
  1130  				Detached: true,
  1131  			},
  1132  			{
  1133  				Name:    `(NOT detached) payload does not contain a period`,
  1134  				Payload: []byte(`hell0w0rld`),
  1135  			},
  1136  		}
  1137  
  1138  		for _, tc := range testcases {
  1139  			tc := tc
  1140  			t.Run(tc.Name, func(t *testing.T) {
  1141  				hdrs := jws.NewHeaders()
  1142  				hdrs.Set("b64", false)
  1143  				hdrs.Set("crit", "b64")
  1144  
  1145  				payload := tc.Payload
  1146  				signOptions := []jws.SignOption{jws.WithKey(jwa.HS256, key, jws.WithProtectedHeaders(hdrs))}
  1147  				var verifyOptions []jws.VerifyOption
  1148  				verifyOptions = append(verifyOptions, jws.WithKey(jwa.HS256, key))
  1149  				if tc.Detached {
  1150  					signOptions = append(signOptions, jws.WithDetachedPayload(payload))
  1151  					verifyOptions = append(verifyOptions, jws.WithDetachedPayload(payload))
  1152  					payload = nil
  1153  				}
  1154  				signed, err := jws.Sign(payload, signOptions...)
  1155  				require.NoError(t, err, `jws.Sign should succeed`)
  1156  
  1157  				verified, err := jws.Verify(signed, verifyOptions...)
  1158  				require.NoError(t, err, `jws.Verify should succeed`)
  1159  				require.Equal(t, tc.Payload, verified, `payload should match`)
  1160  			})
  1161  		}
  1162  	})
  1163  
  1164  	t.Run("Verify", func(t *testing.T) {
  1165  		detached := []byte(`$.02`)
  1166  		testcases := []struct {
  1167  			Name          string
  1168  			Input         []byte
  1169  			VerifyOptions []jws.VerifyOption
  1170  			Error         bool
  1171  		}{
  1172  			{
  1173  				Name: "JSON format",
  1174  				Input: []byte(`{
  1175        "protected": "eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19",
  1176        "payload": "$.02",
  1177        "signature": "A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY"
  1178       }`),
  1179  			},
  1180  			{
  1181  				Name: "JSON format (detached payload)",
  1182  				VerifyOptions: []jws.VerifyOption{
  1183  					jws.WithDetachedPayload(detached),
  1184  				},
  1185  				Input: []byte(`{
  1186        "protected": "eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19",
  1187        "signature": "A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY"
  1188       }`),
  1189  			},
  1190  			{
  1191  				Name:  "JSON Format (b64 does not match)",
  1192  				Error: true,
  1193  				Input: []byte(`{
  1194  					"signatures": [
  1195  						{
  1196  							"protected": "eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19",
  1197  				            "signature": "A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY"
  1198  						},
  1199  						{
  1200  							"protected": "eyJhbGciOiJIUzI1NiIsImI2NCI6dHJ1ZSwiY3JpdCI6WyJiNjQiXX0", 
  1201  							"signature": "6BjugbC8MfrT_yy5WxWVFZrEHVPDtpdsV9u-wbzQDV8"
  1202  						}
  1203  					],
  1204  					"payload":"$.02"
  1205  				}`),
  1206  			},
  1207  			{
  1208  				Name:  "Compact (detached payload)",
  1209  				Input: []byte(`eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY`),
  1210  				VerifyOptions: []jws.VerifyOption{
  1211  					jws.WithDetachedPayload(detached),
  1212  				},
  1213  			},
  1214  		}
  1215  
  1216  		for _, tc := range testcases {
  1217  			tc := tc
  1218  			t.Run(tc.Name, func(t *testing.T) {
  1219  				options := tc.VerifyOptions
  1220  				options = append(options, jws.WithKey(jwa.HS256, key))
  1221  				payload, err := jws.Verify(tc.Input, options...)
  1222  				if tc.Error {
  1223  					require.Error(t, err, `jws.Verify should fail`)
  1224  					require.False(t, jws.IsVerificationError(err), `jws.IsVerifyError should return false`)
  1225  				} else {
  1226  					require.NoError(t, err, `jws.Verify should succeed`)
  1227  					require.Equal(t, detached, payload, `payload should match`)
  1228  				}
  1229  			})
  1230  		}
  1231  	})
  1232  }
  1233  
  1234  func TestGH485(t *testing.T) {
  1235  	const payload = `eyJhIjoiYiJ9`
  1236  	const protected = `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImNyaXQiOlsiZXhwIl0sImV4cCI6MCwiaXNzIjoiZm9vIiwibmJmIjowLCJpYXQiOjB9`
  1237  	const signature = `qM0CdRcyR4hw03J2ThJDat3Af40U87wVCF3Tp3xsyOg`
  1238  	const expected = `{"a":"b"}`
  1239  	signed := fmt.Sprintf(`{
  1240      "payload": %q,
  1241      "signatures": [{"protected": %q, "signature": %q}]
  1242  }`, payload, protected, signature)
  1243  
  1244  	verified, err := jws.Verify([]byte(signed), jws.WithKey(jwa.HS256, []byte("secret")))
  1245  	require.NoError(t, err, `jws.Verify should succeed`)
  1246  	require.Equal(t, expected, string(verified), `verified payload should match`)
  1247  
  1248  	compact := strings.Join([]string{protected, payload, signature}, ".")
  1249  	verified, err = jws.Verify([]byte(compact), jws.WithKey(jwa.HS256, []byte("secret")))
  1250  	require.NoError(t, err, `jws.Verify should succeed`)
  1251  	require.Equal(t, expected, string(verified), `verified payload should match`)
  1252  }
  1253  
  1254  func TestJKU(t *testing.T) {
  1255  	key, err := jwxtest.GenerateRsaJwk()
  1256  	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
  1257  
  1258  	key.Set(jwk.KeyIDKey, `my-awesome-key`)
  1259  
  1260  	pubkey, err := jwk.PublicKeyOf(key)
  1261  	require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
  1262  	set := jwk.NewSet()
  1263  	set.AddKey(pubkey)
  1264  	srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1265  		w.WriteHeader(http.StatusOK)
  1266  		json.NewEncoder(w).Encode(set)
  1267  	}))
  1268  	defer srv.Close()
  1269  
  1270  	payload := []byte("Lorem Ipsum")
  1271  
  1272  	t.Run("Compact", func(t *testing.T) {
  1273  		testcases := []struct {
  1274  			Name         string
  1275  			Error        bool
  1276  			Query        string
  1277  			Fetcher      func() jwk.Fetcher
  1278  			FetchOptions func() []jwk.FetchOption
  1279  		}{
  1280  			{
  1281  				Name:  "Fail without whitelist",
  1282  				Error: true,
  1283  				FetchOptions: func() []jwk.FetchOption {
  1284  					return []jwk.FetchOption{jwk.WithHTTPClient(srv.Client())}
  1285  				},
  1286  			},
  1287  			{
  1288  				Name: "Success",
  1289  				FetchOptions: func() []jwk.FetchOption {
  1290  					return []jwk.FetchOption{
  1291  						jwk.WithFetchWhitelist(jwk.InsecureWhitelist{}),
  1292  						jwk.WithHTTPClient(srv.Client()),
  1293  					}
  1294  				},
  1295  			},
  1296  			{
  1297  				Name:  "Rejected by whitelist",
  1298  				Error: true,
  1299  				FetchOptions: func() []jwk.FetchOption {
  1300  					wl := jwk.NewMapWhitelist().Add(`https://github.com/lestrrat-go/jwx/v2`)
  1301  					return []jwk.FetchOption{
  1302  						jwk.WithFetchWhitelist(wl),
  1303  						jwk.WithHTTPClient(srv.Client()),
  1304  					}
  1305  				},
  1306  			},
  1307  			{
  1308  				Name: "JWKFetcher",
  1309  				Fetcher: func() jwk.Fetcher {
  1310  					c := jwk.NewCache(context.TODO())
  1311  					return jwk.FetchFunc(func(ctx context.Context, u string, options ...jwk.FetchOption) (jwk.Set, error) {
  1312  						var cacheopts []jwk.RegisterOption
  1313  						for _, option := range options {
  1314  							cacheopts = append(cacheopts, option)
  1315  						}
  1316  						cacheopts = append(cacheopts, jwk.WithHTTPClient(srv.Client()))
  1317  						cacheopts = append(cacheopts, jwk.WithFetchWhitelist(httprc.InsecureWhitelist{}))
  1318  						c.Register(u, cacheopts...)
  1319  
  1320  						return c.Get(ctx, u)
  1321  					})
  1322  				},
  1323  			},
  1324  		}
  1325  
  1326  		for _, tc := range testcases {
  1327  			tc := tc
  1328  			t.Run(tc.Name, func(t *testing.T) {
  1329  				hdr := jws.NewHeaders()
  1330  				u := srv.URL
  1331  				if tc.Query != "" {
  1332  					u += "?" + tc.Query
  1333  				}
  1334  				hdr.Set(jws.JWKSetURLKey, u)
  1335  				signed, err := jws.Sign(payload, jws.WithKey(jwa.RS256, key, jws.WithProtectedHeaders(hdr)))
  1336  				require.NoError(t, err, `jws.Sign should succeed`)
  1337  
  1338  				var options []jwk.FetchOption
  1339  				if f := tc.FetchOptions; f != nil {
  1340  					options = append(options, f()...)
  1341  				}
  1342  
  1343  				var fetcher jwk.Fetcher
  1344  				if f := tc.Fetcher; f != nil {
  1345  					fetcher = f()
  1346  				}
  1347  				decoded, err := jws.Verify(signed, jws.WithVerifyAuto(fetcher, options...))
  1348  				if tc.Error {
  1349  					require.Error(t, err, `jws.Verify should fail`)
  1350  				} else {
  1351  					require.NoError(t, err, `jws.Verify should succeed`)
  1352  					require.Equal(t, payload, decoded, `decoded payload should match`)
  1353  				}
  1354  			})
  1355  		}
  1356  	})
  1357  	t.Run("JSON", func(t *testing.T) {
  1358  		// scenario: create a JSON message, which contains 3 signature entries.
  1359  		// 1st and 3rd signatures are valid, but signed using keys that are not
  1360  		// present in the JWKS.
  1361  		// Only the second signature uses a key found in the JWKS
  1362  		var keys []jwk.Key
  1363  		for i := 0; i < 3; i++ {
  1364  			key, err := jwxtest.GenerateRsaJwk()
  1365  			require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
  1366  			key.Set(jwk.KeyIDKey, fmt.Sprintf(`used-%d`, i))
  1367  			keys = append(keys, key)
  1368  		}
  1369  
  1370  		var unusedKeys []jwk.Key
  1371  		for i := 0; i < 2; i++ {
  1372  			key, err := jwxtest.GenerateRsaJwk()
  1373  			require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
  1374  			key.Set(jwk.KeyIDKey, fmt.Sprintf(`unused-%d`, i))
  1375  			unusedKeys = append(unusedKeys, key)
  1376  		}
  1377  
  1378  		// The set should contain unused key, used key, and unused key.
  1379  		// ...but they need to be public keys
  1380  		set := jwk.NewSet()
  1381  		for _, key := range []jwk.Key{unusedKeys[0], keys[1], unusedKeys[1]} {
  1382  			pubkey, err := jwk.PublicKeyOf(key)
  1383  			require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
  1384  			require.Equal(t, pubkey.KeyID(), key.KeyID(), `key ID should be populated`)
  1385  			set.AddKey(pubkey)
  1386  		}
  1387  		srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1388  			w.WriteHeader(http.StatusOK)
  1389  			json.NewEncoder(w).Encode(set)
  1390  		}))
  1391  		defer srv.Close()
  1392  
  1393  		// Sign the payload using the three keys
  1394  		var signOptions = []jws.SignOption{jws.WithJSON()}
  1395  		for _, key := range keys {
  1396  			hdr := jws.NewHeaders()
  1397  			hdr.Set(jws.JWKSetURLKey, srv.URL)
  1398  			signOptions = append(signOptions, jws.WithKey(jwa.RS256, key, jws.WithProtectedHeaders(hdr)))
  1399  		}
  1400  
  1401  		signed, err := jws.Sign(payload, signOptions...)
  1402  		require.NoError(t, err, `jws.SignMulti should succeed`)
  1403  
  1404  		testcases := []struct {
  1405  			Name         string
  1406  			FetchOptions func() []jwk.FetchOption
  1407  			Error        bool
  1408  		}{
  1409  			{
  1410  				Name:  "Fail without whitelist",
  1411  				Error: true,
  1412  			},
  1413  			{
  1414  				Name: "Success",
  1415  				FetchOptions: func() []jwk.FetchOption {
  1416  					return []jwk.FetchOption{
  1417  						jwk.WithFetchWhitelist(jwk.InsecureWhitelist{}),
  1418  					}
  1419  				},
  1420  			},
  1421  			{
  1422  				Name:  "Rejected by whitelist",
  1423  				Error: true,
  1424  				FetchOptions: func() []jwk.FetchOption {
  1425  					wl := jwk.NewMapWhitelist().Add(`https://github.com/lestrrat-go/jwx/v2`)
  1426  					return []jwk.FetchOption{
  1427  						jwk.WithFetchWhitelist(wl),
  1428  					}
  1429  				},
  1430  			},
  1431  		}
  1432  
  1433  		for _, tc := range testcases {
  1434  			tc := tc
  1435  			t.Run(tc.Name, func(t *testing.T) {
  1436  				m := jws.NewMessage()
  1437  				var options []jwk.FetchOption
  1438  				if fn := tc.FetchOptions; fn != nil {
  1439  					options = fn()
  1440  				}
  1441  				options = append(options, jwk.WithHTTPClient(srv.Client()))
  1442  
  1443  				decoded, err := jws.Verify(signed, jws.WithVerifyAuto(nil, options...), jws.WithMessage(m))
  1444  				if tc.Error {
  1445  					require.Error(t, err, `jws.Verify should fail`)
  1446  				} else {
  1447  					if !assert.NoError(t, err, `jws.Verify should succeed`) {
  1448  						set, _ := jwk.Fetch(context.Background(), srv.URL, options...)
  1449  						{
  1450  							buf, _ := json.MarshalIndent(set, "", "  ")
  1451  							t.Logf("%s", buf)
  1452  						}
  1453  						return
  1454  					}
  1455  					require.Equal(t, payload, decoded, `decoded payload should match`)
  1456  					// XXX This actally doesn't really test much, but if there was anything
  1457  					// wrong, the process should have failed well before reaching here
  1458  					require.Equal(t, payload, m.Payload(), "message payload matches")
  1459  				}
  1460  			})
  1461  		}
  1462  	})
  1463  }
  1464  
  1465  func TestAlgorithmsForKey(t *testing.T) {
  1466  	rsaprivkey, err := jwxtest.GenerateRsaJwk()
  1467  	require.NoError(t, err, `jwxtest.GenerateRsaPrivateKey should succeed`)
  1468  	rsapubkey, err := rsaprivkey.PublicKey()
  1469  	require.NoError(t, err, `jwk (RSA) PublicKey() should succeed`)
  1470  
  1471  	ecdsaprivkey, err := jwxtest.GenerateEcdsaJwk()
  1472  	require.NoError(t, err, `jwxtest.GenerateEcdsaPrivateKey should succeed`)
  1473  	ecdsapubkey, err := ecdsaprivkey.PublicKey()
  1474  	require.NoError(t, err, `jwk (ECDSA) PublicKey() should succeed`)
  1475  
  1476  	testcases := []struct {
  1477  		Name     string
  1478  		Key      interface{}
  1479  		Expected []jwa.SignatureAlgorithm
  1480  	}{
  1481  		{
  1482  			Name:     "Octet sequence",
  1483  			Key:      []byte("hello"),
  1484  			Expected: []jwa.SignatureAlgorithm{jwa.HS256, jwa.HS384, jwa.HS512},
  1485  		},
  1486  		{
  1487  			Name:     "rsa.PublicKey",
  1488  			Key:      rsa.PublicKey{},
  1489  			Expected: []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512},
  1490  		},
  1491  		{
  1492  			Name:     "*rsa.PublicKey",
  1493  			Key:      &rsa.PublicKey{},
  1494  			Expected: []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512},
  1495  		},
  1496  		{
  1497  			Name:     "jwk.RSAPublicKey",
  1498  			Key:      rsapubkey,
  1499  			Expected: []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512},
  1500  		},
  1501  		{
  1502  			Name:     "ecdsa.PublicKey",
  1503  			Key:      ecdsa.PublicKey{},
  1504  			Expected: []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512},
  1505  		},
  1506  		{
  1507  			Name:     "*ecdsa.PublicKey",
  1508  			Key:      &ecdsa.PublicKey{},
  1509  			Expected: []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512},
  1510  		},
  1511  		{
  1512  			Name:     "jwk.ECDSAPublicKey",
  1513  			Key:      ecdsapubkey,
  1514  			Expected: []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512},
  1515  		},
  1516  		{
  1517  			Name:     "rsa.PrivateKey",
  1518  			Key:      rsa.PrivateKey{},
  1519  			Expected: []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512},
  1520  		},
  1521  		{
  1522  			Name:     "*rsa.PrivateKey",
  1523  			Key:      &rsa.PrivateKey{},
  1524  			Expected: []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512},
  1525  		},
  1526  		{
  1527  			Name:     "jwk.RSAPrivateKey",
  1528  			Key:      rsapubkey,
  1529  			Expected: []jwa.SignatureAlgorithm{jwa.RS256, jwa.RS384, jwa.RS512, jwa.PS256, jwa.PS384, jwa.PS512},
  1530  		},
  1531  		{
  1532  			Name:     "ecdsa.PrivateKey",
  1533  			Key:      ecdsa.PrivateKey{},
  1534  			Expected: []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512},
  1535  		},
  1536  		{
  1537  			Name:     "*ecdsa.PrivateKey",
  1538  			Key:      &ecdsa.PrivateKey{},
  1539  			Expected: []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512},
  1540  		},
  1541  		{
  1542  			Name:     "jwk.ECDSAPrivateKey",
  1543  			Key:      ecdsaprivkey,
  1544  			Expected: []jwa.SignatureAlgorithm{jwa.ES256, jwa.ES384, jwa.ES512},
  1545  		},
  1546  		{
  1547  			Name:     "ed25519.PublicKey",
  1548  			Key:      ed25519.PublicKey(nil),
  1549  			Expected: []jwa.SignatureAlgorithm{jwa.EdDSA},
  1550  		},
  1551  		{
  1552  			Name:     "x25519.PublicKey",
  1553  			Key:      x25519.PublicKey(nil),
  1554  			Expected: []jwa.SignatureAlgorithm{jwa.EdDSA},
  1555  		},
  1556  	}
  1557  
  1558  	for _, tc := range testcases {
  1559  		tc := tc
  1560  
  1561  		if hasES256K {
  1562  			if strings.Contains(strings.ToLower(tc.Name), `ecdsa`) {
  1563  				tc.Expected = append(tc.Expected, jwa.ES256K)
  1564  			}
  1565  		}
  1566  
  1567  		sort.Slice(tc.Expected, func(i, j int) bool {
  1568  			return tc.Expected[i].String() < tc.Expected[j].String()
  1569  		})
  1570  		t.Run(tc.Name, func(t *testing.T) {
  1571  			algs, err := jws.AlgorithmsForKey(tc.Key)
  1572  			require.NoError(t, err, `jws.AlgorithmsForKey should succeed`)
  1573  
  1574  			sort.Slice(algs, func(i, j int) bool {
  1575  				return algs[i].String() < algs[j].String()
  1576  			})
  1577  			require.Equal(t, tc.Expected, algs, `results should match`)
  1578  		})
  1579  	}
  1580  }
  1581  
  1582  func TestGH681(t *testing.T) {
  1583  	privkey, err := jwxtest.GenerateRsaKey()
  1584  	require.NoError(t, err, "failed to create private key")
  1585  
  1586  	buf, err := jws.Sign(nil, jws.WithKey(jwa.RS256, privkey), jws.WithDetachedPayload([]byte("Lorem ipsum")))
  1587  	require.NoError(t, err, "failed to sign payload")
  1588  
  1589  	t.Logf("%s", buf)
  1590  
  1591  	_, err = jws.Verify(buf, jws.WithKey(jwa.RS256, &privkey.PublicKey), jws.WithDetachedPayload([]byte("Lorem ipsum")))
  1592  	require.NoError(t, err, "failed to verify JWS message")
  1593  }
  1594  
  1595  func TestGH840(t *testing.T) {
  1596  	// Go 1.19+ panics if elliptic curve operations are called against
  1597  	// a point that's _NOT_ on the curve
  1598  	untrustedJWK := []byte(`{
  1599  		"kty": "EC",
  1600  		"crv": "P-256",
  1601  		"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqx7D4",
  1602  		"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
  1603  		"d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"
  1604  	}`)
  1605  
  1606  	// Parse, serialize, slice and dice JWKs!
  1607  	privkey, err := jwk.ParseKey(untrustedJWK)
  1608  	require.NoError(t, err, `jwk.ParseKey should succeed`)
  1609  
  1610  	pubkey, err := jwk.PublicKeyOf(privkey)
  1611  	require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
  1612  
  1613  	tok, err := jwt.NewBuilder().
  1614  		Issuer(`github.com/lestrrat-go/jwx`).
  1615  		IssuedAt(time.Now()).
  1616  		Build()
  1617  	require.NoError(t, err, `jwt.NewBuilder should succeed`)
  1618  
  1619  	signed, err := jwt.Sign(tok, jwt.WithKey(jwa.ES256, privkey))
  1620  	require.NoError(t, err, `jwt.Sign should succeed`)
  1621  
  1622  	_, err = jwt.Parse(signed, jwt.WithKey(jwa.ES256, pubkey))
  1623  	require.Error(t, err, `jwt.Parse should FAIL`) // pubkey's X/Y is not on the curve
  1624  }
  1625  
  1626  func TestGH888(t *testing.T) {
  1627  	// This should fail because we're passing multiple keys (i.e. multiple signatures)
  1628  	// and yet we haven't specified JSON serialization
  1629  	_, err := jws.Sign([]byte(`foo`), jws.WithInsecureNoSignature(), jws.WithKey(jwa.HS256, []byte(`bar`)))
  1630  	require.Error(t, err, `jws.Sign with multiple keys (including alg=none) should fail`)
  1631  
  1632  	// This should pass because we can now have multiple signaures with JSON serialization
  1633  	signed, err := jws.Sign([]byte(`foo`), jws.WithInsecureNoSignature(), jws.WithKey(jwa.HS256, []byte(`bar`)), jws.WithJSON())
  1634  	require.NoError(t, err, `jws.Sign should succeed`)
  1635  
  1636  	message, err := jws.Parse(signed)
  1637  	require.NoError(t, err, `jws.Parse should succeed`)
  1638  
  1639  	// Look for alg=none signature
  1640  	var foundNoSignature bool
  1641  	for _, sig := range message.Signatures() {
  1642  		if sig.ProtectedHeaders().Algorithm() != jwa.NoSignature {
  1643  			continue
  1644  		}
  1645  
  1646  		require.Nil(t, sig.Signature(), `signature must be nil for alg=none`)
  1647  		foundNoSignature = true
  1648  	}
  1649  	require.True(t, foundNoSignature, `signature with no signature was found`)
  1650  
  1651  	_, err = jws.Verify(signed)
  1652  	require.Error(t, err, `jws.Verify should fail`)
  1653  
  1654  	_, err = jws.Verify(signed, jws.WithKey(jwa.NoSignature, nil))
  1655  	require.Error(t, err, `jws.Verify should fail`)
  1656  
  1657  	// Note: you can't do jws.Verify(..., jws.WithInsecureNoSignature())
  1658  
  1659  	verified, err := jws.Verify(signed, jws.WithKey(jwa.HS256, []byte(`bar`)))
  1660  	require.NoError(t, err, `jws.Verify should succeed`)
  1661  	require.Equal(t, []byte(`foo`), verified)
  1662  }
  1663  
  1664  // Some stuff required for testing #910
  1665  // The original code used an external library to sign/verify, but here
  1666  // we just use a simple SHA256 digest here so that we don't force
  1667  // users to download an optional dependency
  1668  type s256SignerVerifier struct{}
  1669  
  1670  const sha256Algo jwa.SignatureAlgorithm = "SillyTest256"
  1671  
  1672  func (s256SignerVerifier) Algorithm() jwa.SignatureAlgorithm {
  1673  	return sha256Algo
  1674  }
  1675  
  1676  func (s256SignerVerifier) Sign(payload []byte, _ interface{}) ([]byte, error) {
  1677  	h := sha256.Sum256(payload)
  1678  	return h[:], nil
  1679  }
  1680  
  1681  func (s256SignerVerifier) Verify(payload, signature []byte, _ interface{}) error {
  1682  	h := sha256.Sum256(payload)
  1683  	if !bytes.Equal(h[:], signature) {
  1684  		return errors.New("invalid signature")
  1685  	}
  1686  	return nil
  1687  }
  1688  
  1689  func TestGH910(t *testing.T) {
  1690  	// Note: This has global effect. You can't run this in parallel with other tests
  1691  	jws.RegisterSigner(sha256Algo, jws.SignerFactoryFn(func() (jws.Signer, error) {
  1692  		return s256SignerVerifier{}, nil
  1693  	}))
  1694  	defer jws.UnregisterSigner(sha256Algo)
  1695  
  1696  	jws.RegisterVerifier(sha256Algo, jws.VerifierFactoryFn(func() (jws.Verifier, error) {
  1697  		return s256SignerVerifier{}, nil
  1698  	}))
  1699  	defer jws.UnregisterVerifier(sha256Algo)
  1700  	defer jwa.UnregisterSignatureAlgorithm(sha256Algo)
  1701  
  1702  	var sa jwa.SignatureAlgorithm
  1703  	require.NoError(t, sa.Accept(sha256Algo.String()), `jwa.SignatureAlgorithm.Accept should succeed`)
  1704  
  1705  	// Now that we have established that the signature algorithm works,
  1706  	// we can proceed with the test
  1707  	const src = `Lorem Ipsum`
  1708  	signed, err := jws.Sign([]byte(src), jws.WithKey(sha256Algo, nil))
  1709  	require.NoError(t, err, `jws.Sign should succeed`)
  1710  
  1711  	verified, err := jws.Verify(signed, jws.WithKey(sha256Algo, nil))
  1712  	require.NoError(t, err, `jws.Verify should succeed`)
  1713  
  1714  	require.Equal(t, src, string(verified), `verified payload should match`)
  1715  
  1716  	jws.UnregisterSigner(sha256Algo)
  1717  
  1718  	// Now try after unregistering the signer for the algorithm
  1719  	_, err = jws.Sign([]byte(src), jws.WithKey(sha256Algo, nil))
  1720  	require.Error(t, err, `jws.Sign should succeed`)
  1721  
  1722  	jws.RegisterSigner(sha256Algo, jws.SignerFactoryFn(func() (jws.Signer, error) {
  1723  		return s256SignerVerifier{}, nil
  1724  	}))
  1725  
  1726  	_, err = jws.Sign([]byte(src), jws.WithKey(sha256Algo, nil))
  1727  	require.NoError(t, err, `jws.Sign should succeed`)
  1728  }
  1729  
  1730  func TestUnpaddedSignatureR(t *testing.T) {
  1731  	// I brute-forced generating a key and signature where the R portion
  1732  	// of the signature was not padded by using the following code in the
  1733  	// first run, then copied the result to the test
  1734  	/*
  1735  		for i := 0; i < 10000; i++ {
  1736  			rawKey, err := jwxtest.GenerateEcdsaKey(jwa.P256)
  1737  			require.NoError(t, err, `jwxtest.GenerateEcdsaJwk should succeed`)
  1738  
  1739  			key, err := jwk.FromRaw(rawKey)
  1740  			require.NoError(t, err, `jwk.FromRaw should succeed`)
  1741  
  1742  			pubkey, _ := key.PublicKey()
  1743  
  1744  			signed, err := jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.ES256, key))
  1745  			require.NoError(t, err, `jws.Sign should succeed`)
  1746  
  1747  			message, err := jws.Parse(signed)
  1748  			require.NoError(t, err, `jws.Parse should succeed`)
  1749  
  1750  			asJson, _ := json.Marshal(message)
  1751  			t.Logf("%s", asJson)
  1752  
  1753  			for _, sig := range message.Signatures() {
  1754  				sigBytes := sig.Signature()
  1755  				if sigBytes[0] == 0x00 {
  1756  					// Found it!
  1757  					t.Logf("Found signature that can be unpadded.")
  1758  					t.Logf("Original signature: %q", base64.EncodeToString(sigBytes))
  1759  
  1760  					//				unpaddedSig := append(sigBytes[1:31], sigBytes[32:]...)
  1761  					unpaddedSig := sigBytes[1:]
  1762  					t.Logf("Signature with first byte of R removed: %q", base64.EncodeToString(unpaddedSig))
  1763  					t.Logf("Original JWS payload: %q", signed)
  1764  					require.Len(t, unpaddedSig, 63)
  1765  
  1766  					i := bytes.LastIndexByte(signed, '.')
  1767  					modified := append(signed[:i+1], base64.Encode(unpaddedSig)...)
  1768  					t.Logf("JWS payload with unpadded signature: %q", modified)
  1769  
  1770  					// jws.Verify for sanity
  1771  					verified, err := jws.Verify(modified, jws.WithKey(jwa.ES256, pubkey))
  1772  					require.NoError(t, err, `jws.Verify should succeed`)
  1773  					t.Logf("verified payload: %q", verified)
  1774  
  1775  					buf, _ := json.Marshal(key)
  1776  					t.Logf("Private JWK: %s", buf)
  1777  					return
  1778  				}
  1779  			}
  1780  		}
  1781  	*/
  1782  	// Padded has R with a leading 0 (as it should)
  1783  	padded := "eyJhbGciOiJFUzI1NiJ9.TG9yZW0gSXBzdW0.ALFru4CRZDiAlVKyyHtlLGtXIAWxC3lXIlZuYO8G8a5ePzCwyw6c2FzWBZwrLaoLFZb_TcYs3TcZ8mhONPaavQ"
  1784  	// Unpadded has R with a leading 0 removed (31 bytes, WRONG)
  1785  	unpadded := "eyJhbGciOiJFUzI1NiJ9.TG9yZW0gSXBzdW0.sWu7gJFkOICVUrLIe2Usa1cgBbELeVciVm5g7wbxrl4_MLDLDpzYXNYFnCstqgsVlv9NxizdNxnyaE409pq9"
  1786  
  1787  	// This is the private key used to sign the payload
  1788  	keySrc := `{"crv":"P-256","d":"MqGwMl-dlJFrMnu7rFyslPV8EdsVC7I4V19N-ADVqaU","kty":"EC","x":"Anf1p2lRrcXgZKpVRRC1xLxPiw_45PbOlygfbxvD8Es","y":"d0HiZq-aurVVLLtK-xqXPpzpWloZJNwKNve7akBDuvg"}`
  1789  
  1790  	privKey, err := jwk.ParseKey([]byte(keySrc))
  1791  	require.NoError(t, err, `jwk.ParseKey should succeed`)
  1792  
  1793  	pubKey, err := jwk.PublicKeyOf(privKey)
  1794  	require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
  1795  
  1796  	// Should always succeed
  1797  	payload, err := jws.Verify([]byte(padded), jws.WithKey(jwa.ES256, pubKey))
  1798  	require.NoError(t, err, `jws.Verify should succeed`)
  1799  	require.Equal(t, "Lorem Ipsum", string(payload))
  1800  
  1801  	// Should fail
  1802  	_, err = jws.Verify([]byte(unpadded), jws.WithKey(jwa.ES256, pubKey))
  1803  	require.Error(t, err, `jws.Verify should fail`)
  1804  }
  1805  
  1806  func TestValidateKey(t *testing.T) {
  1807  	privKey, err := jwxtest.GenerateRsaJwk()
  1808  	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
  1809  
  1810  	signed, err := jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.RS256, privKey), jws.WithValidateKey(true))
  1811  	require.NoError(t, err, `jws.Sign should succeed`)
  1812  
  1813  	// This should fail because D is empty
  1814  	require.NoError(t, privKey.Set(jwk.RSADKey, []byte(nil)), `jwk.Set should succeed`)
  1815  	_, err = jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.RS256, privKey), jws.WithValidateKey(true))
  1816  	require.Error(t, err, `jws.Sign should fail`)
  1817  
  1818  	pubKey, err := jwk.PublicKeyOf(privKey)
  1819  	require.NoError(t, err, `jwk.PublicKeyOf should succeed`)
  1820  
  1821  	n := pubKey.(jwk.RSAPublicKey).N()
  1822  
  1823  	// Set N to an empty value
  1824  	require.NoError(t, pubKey.Set(jwk.RSANKey, []byte(nil)), `jwk.Set should succeed`)
  1825  
  1826  	// This is going to fail regardless, because the public key is now
  1827  	// invalid (empty N), but we want to make sure that it fails because
  1828  	// of the validation failing
  1829  	_, err = jws.Verify(signed, jws.WithKey(jwa.RS256, pubKey), jws.WithValidateKey(true))
  1830  	require.Error(t, err, `jws.Verify should fail`)
  1831  	require.True(t, jwk.IsKeyValidationError(err), `jwk.IsKeyValidationError should return true`)
  1832  
  1833  	// The following should now succeed, because N has been reinstated
  1834  	require.NoError(t, pubKey.Set(jwk.RSANKey, n), `jwk.Set should succeed`)
  1835  	_, err = jws.Verify(signed, jws.WithKey(jwa.RS256, pubKey), jws.WithValidateKey(true))
  1836  	require.NoError(t, err, `jws.Verify should succeed`)
  1837  }
  1838  
  1839  func TestEmptyProtectedField(t *testing.T) {
  1840  	// MEMO: this was the only test case from the original report
  1841  	// This passes. It should produce an invalid JWS message, but
  1842  	// that's not `jws.Parse`'s problem.
  1843  	_, err := jws.Parse([]byte(`{"signature": ""}`))
  1844  	require.NoError(t, err, `jws.Parse should fail`)
  1845  
  1846  	// Also test that non-flattened serialization passes.
  1847  	_, err = jws.Parse([]byte(`{"signatures": [{}]}`))
  1848  	require.NoError(t, err, `jws.Parse should fail`)
  1849  
  1850  	// MEMO: rest of the cases are present to be extra pedantic about it
  1851  
  1852  	privKey, err := jwxtest.GenerateRsaJwk()
  1853  	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
  1854  
  1855  	// This fails. `jws.Parse` works, but the subsequent verification
  1856  	// workflow fails to verify anything without the presence of a signature or
  1857  	// a protected header.
  1858  	_, err = jws.Verify([]byte(`{"signature": ""}`), jws.WithKey(jwa.RS256, privKey))
  1859  	require.Error(t, err, `jws.Parse should fail`)
  1860  
  1861  	// Create a valid signatre.
  1862  	signed, err := jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.RS256, privKey))
  1863  	require.NoError(t, err, `jws.Sign should succeed`)
  1864  
  1865  	_, payload, signature, err := jws.SplitCompact(signed)
  1866  	require.NoError(t, err, `jws.SplitCompact should succeed`)
  1867  
  1868  	// This fails as well. we have a valid signature and a valid
  1869  	// key to verify it, but no protected headers
  1870  	_, err = jws.Verify(
  1871  		[]byte(fmt.Sprintf(`{"signature": "%s"}`, signature)),
  1872  		jws.WithKey(jwa.RS256, privKey),
  1873  	)
  1874  	require.Error(t, err, `jws.Verify should fail`)
  1875  
  1876  	// Test for cases when we have an incomplete compact form JWS
  1877  	var buf bytes.Buffer
  1878  	buf.WriteRune('.')
  1879  	buf.Write(payload)
  1880  	buf.WriteRune('.')
  1881  	buf.Write(signature)
  1882  	invalidMessage := buf.Bytes()
  1883  
  1884  	// This is an error because the format is simply wrong.
  1885  	// Whereas in the other JSON-based JWS's case the lack of protected field
  1886  	// is not a SYNTAX error, this one is, and therefore we barf.
  1887  	_, err = jws.Parse(invalidMessage)
  1888  	require.Error(t, err, `jws.Parse should fail`)
  1889  }
  1890  
  1891  func TestParseFormat(t *testing.T) {
  1892  	privKey, err := jwxtest.GenerateRsaJwk()
  1893  	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
  1894  
  1895  	signedCompact, err := jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.RS256, privKey), jws.WithValidateKey(true))
  1896  	require.NoError(t, err, `jws.Sign should succeed`)
  1897  
  1898  	signedJSON, err := jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.RS256, privKey), jws.WithValidateKey(true), jws.WithJSON())
  1899  	require.NoError(t, err, `jws.Sign should succeed`)
  1900  
  1901  	// Only compact formats should succeed
  1902  	_, err = jws.Verify(signedCompact, jws.WithKey(jwa.RS256, privKey), jws.WithCompact())
  1903  	require.NoError(t, err, `jws.Verify should succeed`)
  1904  	_, err = jws.Verify(signedJSON, jws.WithKey(jwa.RS256, privKey), jws.WithCompact())
  1905  	require.Error(t, err, `jws.Verify should fail`)
  1906  	_, err = jws.Parse(signedCompact, jws.WithCompact())
  1907  	require.NoError(t, err, `jws.Parse should succeed`)
  1908  	_, err = jws.Parse(signedJSON, jws.WithCompact())
  1909  	require.Error(t, err, `jws.Parse should fail`)
  1910  
  1911  	// Only JSON formats should succeed
  1912  	_, err = jws.Verify(signedCompact, jws.WithKey(jwa.RS256, privKey), jws.WithJSON())
  1913  	require.Error(t, err, `jws.Verify should fail`)
  1914  	_, err = jws.Verify(signedJSON, jws.WithKey(jwa.RS256, privKey), jws.WithJSON())
  1915  	require.NoError(t, err, `jws.Verify should succeed`)
  1916  	_, err = jws.Parse(signedJSON, jws.WithJSON())
  1917  	require.NoError(t, err, `jws.Parse should succeed`)
  1918  	_, err = jws.Parse(signedCompact, jws.WithJSON())
  1919  	require.Error(t, err, `jws.Parse should fail`)
  1920  
  1921  	// Either format should succeed
  1922  	_, err = jws.Verify(signedCompact, jws.WithKey(jwa.RS256, privKey))
  1923  	require.NoError(t, err, `jws.Verify should succeed`)
  1924  	_, err = jws.Verify(signedCompact, jws.WithKey(jwa.RS256, privKey), jws.WithJSON(), jws.WithCompact())
  1925  	require.NoError(t, err, `jws.Verify should succeed`)
  1926  	_, err = jws.Parse(signedCompact)
  1927  	require.NoError(t, err, `jws.Parse should succeed`)
  1928  	_, err = jws.Parse(signedCompact, jws.WithJSON(), jws.WithCompact())
  1929  	require.NoError(t, err, `jws.Parse should succeed`)
  1930  
  1931  	_, err = jws.Verify(signedJSON, jws.WithKey(jwa.RS256, privKey))
  1932  	require.NoError(t, err, `jws.Verify should succeed`)
  1933  	_, err = jws.Verify(signedJSON, jws.WithKey(jwa.RS256, privKey), jws.WithJSON(), jws.WithCompact())
  1934  	require.NoError(t, err, `jws.Verify should succeed`)
  1935  	_, err = jws.Parse(signedJSON)
  1936  	require.NoError(t, err, `jws.Parse should succeed`)
  1937  	_, err = jws.Parse(signedJSON, jws.WithJSON(), jws.WithCompact())
  1938  	require.NoError(t, err, `jws.Parse should succeed`)
  1939  }