Repository: lestrrat-go/jwx
Pull request #1050 (2024-01-08 16:45:29)

Bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 in /examples
Bumps [github.com/cloudflare/circl](https://github.com/cloudflare/circl) from 1.3.3 to 1.3.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/cloudflare/circl/releases">github.com/cloudflare/circl's releases</a>.</em></p>
<blockquote>
<h2>CIRCL v1.3.7</h2>
<h3>What's Changed</h3>
<ul>
<li>build(deps): bump golang.org/x/crypto from 0.3.1-0.20221117191849-2c476679df9a to 0.17.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/467">cloudflare/circl#467</a></li>
<li>kyber: remove division by q in ciphertext compression by <a href="https://github.com/bwesterb"><code>@​bwesterb</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/468">cloudflare/circl#468</a></li>
<li>Releasing CIRCL v1.3.7 by <a href="https://github.com/armfazh"><code>@​armfazh</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/469">cloudflare/circl#469</a></li>
</ul>
<h3>New Contributors</h3>
<ul>
<li><a href="https://github.com/dependabot"><code>@​dependabot</code></a> made their first contribution in <a href="https://redirect.github.com/cloudflare/circl/pull/467">cloudflare/circl#467</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/cloudflare/circl/compare/v1.3.6...v1.3.7">https://github.com/cloudflare/circl/compare/v1.3.6...v1.3.7</a></p>
<h2>CIRCL v1.3.6</h2>
<h3>What's Changed</h3>
<ul>
<li>internal: add TurboShake{128,256} by <a href="https://github.com/bwesterb"><code>@​bwesterb</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/430">cloudflare/circl#430</a></li>
<li>Kangaroo12 draft -10 by <a href="https://github.com/bwesterb"><code>@​bwesterb</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/431">cloudflare/circl#431</a></li>
<li>Add K12 as XOF by <a href="https://github.com/bwesterb"><code>@​bwesterb</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/437">cloudflare/circl#437</a></li>
<li>xof/k12: Fix a typo in the package documentation by <a href="https://github.com/cjpatton"><code>@​cjpatton</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/438">cloudflare/circl#438</a></li>
<li>Set CIRCL version for generated assembler code. by <a href="https://github.com/armfazh"><code>@​armfazh</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/440">cloudflare/circl#440</a></li>
<li>Add tkn20 benchmarks by <a href="https://github.com/tanyav2"><code>@​tanyav2</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/442">cloudflare/circl#442</a></li>
<li>Add partially blind RSA implementation by <a href="https://github.com/chris-wood"><code>@​chris-wood</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/445">cloudflare/circl#445</a></li>
<li>Update doc.go by <a href="https://github.com/nadimkobeissi"><code>@​nadimkobeissi</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/447">cloudflare/circl#447</a></li>
<li>tss/rsa: key generation for threshold RSA (safe primes) by <a href="https://github.com/armfazh"><code>@​armfazh</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/450">cloudflare/circl#450</a></li>
<li>Bumping Go version for CI jobs. by <a href="https://github.com/armfazh"><code>@​armfazh</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/457">cloudflare/circl#457</a></li>
<li>Spelling by <a href="https://github.com/jsoref"><code>@​jsoref</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/456">cloudflare/circl#456</a></li>
<li>blindrsa: updating blindrsa to be compliant with RFC9474 by <a href="https://github.com/armfazh"><code>@​armfazh</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/464">cloudflare/circl#464</a></li>
<li>Releasing CIRCL v1.3.6 by <a href="https://github.com/armfazh"><code>@​armfazh</code></a> in <a href="https://redirect.github.com/cloudflare/circl/pull/465">cloudflare/circl#465</a></li>
</ul>
<h3>New Contributors</h3>
<ul>
<li><a href="https://github.com/nadimkobeissi"><code>@​nadimkobeissi</code></a> made their first contribution in <a href="https://redirect.github.com/cloudflare/circl/pull/447">cloudflare/circl#447</a></li>
<li><a href="https://github.com/jsoref"><code>@​jsoref</code></a> made their first contribution in <a href="https://redirect.github.com/cloudflare/circl/pull/456">cloudflare/circl#456</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/cloudflare/circl/compare/v1.3.3...v1.3.6">https://github.com/cloudflare/circl/compare/v1.3.3...v1.3.6</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/cloudflare/circl/commit/c48866b3068dfa83721c021dec03c777ba91abab"><code>c48866b</code></a> Releasing CIRCL v1.3.7</li>
<li><a href="https://github.com/cloudflare/circl/commit/75ef91e8a2f438e6ce2b6e620d236add8be1887d"><code>75ef91e</code></a> kyber: remove division by q in ciphertext compression</li>
<li><a href="https://github.com/cloudflare/circl/commit/899732a43256a5d6fb779917f597b32939ca4ba4"><code>899732a</code></a> build(deps): bump golang.org/x/crypto</li>
<li><a href="https://github.com/cloudflare/circl/commit/99f0f715ca5fbec868f5a0db1df2be6dcd28dbaa"><code>99f0f71</code></a> Releasing CIRCL v1.3.6</li>
<li><a href="https://github.com/cloudflare/circl/commit/e728d0d84e7e7cd9027050a62aa14adb8dec147c"><code>e728d0d</code></a> Apply thibmeu code review suggestions</li>
<li><a href="https://github.com/cloudflare/circl/commit/ceb2d90c4922ec2e26be09a20f217ee57c8ba1c4"><code>ceb2d90</code></a> Updating blindrsa to be compliant with RFC9474.</li>
<li><a href="https://github.com/cloudflare/circl/commit/44133f703215856ee0b8f243778f24b001ff6c95"><code>44133f7</code></a> spelling: tripped</li>
<li><a href="https://github.com/cloudflare/circl/commit/c2076d67b2c717b1b1c6f3aa3b324bf93079b6fb"><code>c2076d6</code></a> spelling: transposes</li>
<li><a href="https://github.com/cloudflare/circl/commit/dad216659ee1c9969957557a713537ceb589fce5"><code>dad2166</code></a> spelling: title</li>
<li><a href="https://github.com/cloudflare/circl/commit/171c41832e7ec817b9b2873732db6da46bdb1139"><code>171c418</code></a> spelling: threshold</li>
<li>Additional commits viewable in <a href="https://github.com/cloudflare/circl/compare/v1.3.3...v1.3.7">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/cloudflare/circl&package-manager=go_modules&previous-version=1.3.3&new-version=1.3.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/lestrrat-go/jwx/network/alerts).

</details>


Patch:
diff --git a/Changes b/Changes
index cd3dcca2..7c6ae61b 100644
--- a/Changes
+++ b/Changes
@@ -4,12 +4,33 @@ Changes
 v2 has many incompatibilities with v1. To see the full list of differences between
 v1 and v2, please read the Changes-v2.md file (https://github.com/lestrrat-go/jwx/blob/develop/v2/Changes-v2.md)
 
-v2.0.19 UNRELEASED
+v2.0.20 UNRELEASED
+[New Features]
+  * [jwe] Added jwe.Settings(WithMaxBufferSize(int64)) to set the maximum size of
+    internal buffers. The default value is 256MB. Most users do not need to change
+    this value.
+
+[Miscellaneous]
+  * Internal key conversions should now allow private keys to be used in place of
+    public keys. This would allow you to pass private keys where public keys are
+    expected.
+
+v2.0.19 09 Jan 2024
 [New Features]
   * [jws] Added jws.IsVerificationError to check if the error returned by `jws.Verify`
     was caused by actual verification step or something else, for example, while fetching
     a key from datasource
 
+[Security Fixes]
+  * [jws] JWS messages formated in full JSON format (i.e. not the compact format, which
+    consists of three base64 strings concatenated with a '.') with missing "protected"
+    headers could cause a panic, thereby introducing a possiblity of a DoS.
+
+    This has been fixed so that the `jws.Parse` function succeeds in parsing a JWS message
+    lacking a protected header. Calling `jws.Verify` on this same JWS message will result
+    in a failed verification attempt. Note that this behavior will differ slightly when
+    parsing JWS messages in compact form, which result in an error. 
+
 v2.0.18 03 Dec 2023
 [Security Fixes]
   * [jwe] A large number in p2c parameter for PBKDF2 based encryptions could cause a DoS attack,
diff --git a/examples/go.mod b/examples/go.mod
index 5e3c0f5a..bc2ea2f6 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -3,7 +3,7 @@ module github.com/lestrrat-go/jwx/v2/examples
 go 1.16
 
 require (
-	github.com/cloudflare/circl v1.3.3
+	github.com/cloudflare/circl v1.3.7
 	github.com/lestrrat-go/jwx/v2 v2.0.11
 )
 
diff --git a/examples/go.sum b/examples/go.sum
index 67772b16..3f21e040 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -1,6 +1,6 @@
 github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
-github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
-github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
+github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
+github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -35,7 +35,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -43,7 +42,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -55,22 +53,18 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
diff --git a/internal/keyconv/keyconv.go b/internal/keyconv/keyconv.go
index 807da1de..f0ecbae1 100644
--- a/internal/keyconv/keyconv.go
+++ b/internal/keyconv/keyconv.go
@@ -18,7 +18,7 @@ func RSAPrivateKey(dst, src interface{}) error {
 	if jwkKey, ok := src.(jwk.Key); ok {
 		var raw rsa.PrivateKey
 		if err := jwkKey.Raw(&raw); err != nil {
-			return fmt.Errorf(`failed to produce rsa.PrivateKey from %T: %w`, src, err)
+			return fmt.Errorf(`keyconv: failed to produce rsa.PrivateKey from %T: %w`, src, err)
 		}
 		src = &raw
 	}
@@ -30,7 +30,7 @@ func RSAPrivateKey(dst, src interface{}) error {
 	case *rsa.PrivateKey:
 		ptr = src
 	default:
-		return fmt.Errorf(`expected rsa.PrivateKey or *rsa.PrivateKey, got %T`, src)
+		return fmt.Errorf(`keyconv: expected rsa.PrivateKey or *rsa.PrivateKey, got %T`, src)
 	}
 
 	return blackmagic.AssignIfCompatible(dst, ptr)
@@ -41,21 +41,25 @@ func RSAPrivateKey(dst, src interface{}) error {
 // `src` may be rsa.PublicKey, *rsa.PublicKey, or a jwk.Key
 func RSAPublicKey(dst, src interface{}) error {
 	if jwkKey, ok := src.(jwk.Key); ok {
-		var raw rsa.PublicKey
-		if err := jwkKey.Raw(&raw); err != nil {
-			return fmt.Errorf(`failed to produce rsa.PublicKey from %T: %w`, src, err)
+		pk, err := jwk.PublicRawKeyOf(jwkKey)
+		if err != nil {
+			return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err)
 		}
-		src = &raw
+		src = pk
 	}
 
 	var ptr *rsa.PublicKey
 	switch src := src.(type) {
+	case rsa.PrivateKey:
+		ptr = &src.PublicKey
+	case *rsa.PrivateKey:
+		ptr = &src.PublicKey
 	case rsa.PublicKey:
 		ptr = &src
 	case *rsa.PublicKey:
 		ptr = src
 	default:
-		return fmt.Errorf(`expected rsa.PublicKey or *rsa.PublicKey, got %T`, src)
+		return fmt.Errorf(`keyconv: expected rsa.PublicKey/rsa.PrivateKey or *rsa.PublicKey/*rsa.PrivateKey, got %T`, src)
 	}
 
 	return blackmagic.AssignIfCompatible(dst, ptr)
@@ -67,7 +71,7 @@ func ECDSAPrivateKey(dst, src interface{}) error {
 	if jwkKey, ok := src.(jwk.Key); ok {
 		var raw ecdsa.PrivateKey
 		if err := jwkKey.Raw(&raw); err != nil {
-			return fmt.Errorf(`failed to produce ecdsa.PrivateKey from %T: %w`, src, err)
+			return fmt.Errorf(`keyconv: failed to produce ecdsa.PrivateKey from %T: %w`, src, err)
 		}
 		src = &raw
 	}
@@ -79,7 +83,7 @@ func ECDSAPrivateKey(dst, src interface{}) error {
 	case *ecdsa.PrivateKey:
 		ptr = src
 	default:
-		return fmt.Errorf(`expected ecdsa.PrivateKey or *ecdsa.PrivateKey, got %T`, src)
+		return fmt.Errorf(`keyconv: expected ecdsa.PrivateKey or *ecdsa.PrivateKey, got %T`, src)
 	}
 	return blackmagic.AssignIfCompatible(dst, ptr)
 }
@@ -88,21 +92,25 @@ func ECDSAPrivateKey(dst, src interface{}) error {
 // non-pointer to a pointer
 func ECDSAPublicKey(dst, src interface{}) error {
 	if jwkKey, ok := src.(jwk.Key); ok {
-		var raw ecdsa.PublicKey
-		if err := jwkKey.Raw(&raw); err != nil {
-			return fmt.Errorf(`failed to produce ecdsa.PublicKey from %T: %w`, src, err)
+		pk, err := jwk.PublicRawKeyOf(jwkKey)
+		if err != nil {
+			return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err)
 		}
-		src = &raw
+		src = pk
 	}
 
 	var ptr *ecdsa.PublicKey
 	switch src := src.(type) {
+	case ecdsa.PrivateKey:
+		ptr = &src.PublicKey
+	case *ecdsa.PrivateKey:
+		ptr = &src.PublicKey
 	case ecdsa.PublicKey:
 		ptr = &src
 	case *ecdsa.PublicKey:
 		ptr = src
 	default:
-		return fmt.Errorf(`expected ecdsa.PublicKey or *ecdsa.PublicKey, got %T`, src)
+		return fmt.Errorf(`keyconv: expected ecdsa.PublicKey/ecdsa.PrivateKey or *ecdsa.PublicKey/*ecdsa.PrivateKey, got %T`, src)
 	}
 	return blackmagic.AssignIfCompatible(dst, ptr)
 }
@@ -111,13 +119,13 @@ func ByteSliceKey(dst, src interface{}) error {
 	if jwkKey, ok := src.(jwk.Key); ok {
 		var raw []byte
 		if err := jwkKey.Raw(&raw); err != nil {
-			return fmt.Errorf(`failed to produce []byte from %T: %w`, src, err)
+			return fmt.Errorf(`keyconv: failed to produce []byte from %T: %w`, src, err)
 		}
 		src = raw
 	}
 
 	if _, ok := src.([]byte); !ok {
-		return fmt.Errorf(`expected []byte, got %T`, src)
+		return fmt.Errorf(`keyconv: expected []byte, got %T`, src)
 	}
 	return blackmagic.AssignIfCompatible(dst, src)
 }
@@ -145,11 +153,18 @@ func Ed25519PrivateKey(dst, src interface{}) error {
 
 func Ed25519PublicKey(dst, src interface{}) error {
 	if jwkKey, ok := src.(jwk.Key); ok {
-		var raw ed25519.PublicKey
-		if err := jwkKey.Raw(&raw); err != nil {
-			return fmt.Errorf(`failed to produce ed25519.PublicKey from %T: %w`, src, err)
+		pk, err := jwk.PublicRawKeyOf(jwkKey)
+		if err != nil {
+			return fmt.Errorf(`keyconv: failed to produce public key from %T: %w`, src, err)
 		}
-		src = &raw
+		src = pk
+	}
+
+	switch key := src.(type) {
+	case ed25519.PrivateKey:
+		src = key.Public()
+	case *ed25519.PrivateKey:
+		src = key.Public()
 	}
 
 	var ptr *ed25519.PublicKey
diff --git a/jwe/BUILD.bazel b/jwe/BUILD.bazel
index a5e3f4e0..d0a06f0d 100644
--- a/jwe/BUILD.bazel
+++ b/jwe/BUILD.bazel
@@ -25,6 +25,7 @@ go_library(
         "//internal/keyconv",
         "//internal/pool",
         "//jwa",
+        "//jwe/internal/aescbc",
         "//jwe/internal/cipher",
         "//jwe/internal/content_crypt",
         "//jwe/internal/keyenc",
diff --git a/jwe/internal/aescbc/aescbc.go b/jwe/internal/aescbc/aescbc.go
index acb5a83a..749277b9 100644
--- a/jwe/internal/aescbc/aescbc.go
+++ b/jwe/internal/aescbc/aescbc.go
@@ -10,18 +10,42 @@ import (
 	"errors"
 	"fmt"
 	"hash"
+	"sync/atomic"
 )
 
 const (
 	NonceSize = 16
 )
 
+const defaultBufSize int64 = 256 * 1024 * 1024
+
+// Grr, we would like to use atomic.Int64, but that's only available
+// from Go 1.19. Yes, we will cut support for Go 1.19 at some point,
+// but not today (probably going to up the minimum required Go version
+// some time after 1.22 is released)
+var maxBufSize int64
+
+func init() {
+	atomic.StoreInt64(&maxBufSize, defaultBufSize)
+}
+
+func SetMaxBufferSize(siz int64) {
+	if siz <= 0 {
+		siz = defaultBufSize
+	}
+	atomic.StoreInt64(&maxBufSize, siz)
+}
+
 func pad(buf []byte, n int) []byte {
 	rem := n - len(buf)%n
 	if rem == 0 {
 		return buf
 	}
 
+	mbs := atomic.LoadInt64(&maxBufSize)
+	if int64(len(buf)+rem) > mbs {
+		panic(fmt.Errorf("failed to allocate buffer"))
+	}
 	newbuf := make([]byte, len(buf)+rem)
 	copy(newbuf, buf)
 
@@ -174,6 +198,11 @@ func ensureSize(dst []byte, n int) []byte {
 // Seal fulfills the crypto.AEAD interface
 func (c Hmac) Seal(dst, nonce, plaintext, data []byte) []byte {
 	ctlen := len(plaintext)
+	bufsiz := ctlen + c.Overhead()
+	mbs := atomic.LoadInt64(&maxBufSize)
+	if int64(bufsiz) > mbs {
+		panic(fmt.Errorf("failed to allocate buffer"))
+	}
 	ciphertext := make([]byte, ctlen+c.Overhead())[:ctlen]
 	copy(ciphertext, plaintext)
 	ciphertext = pad(ciphertext, c.blockCipher.BlockSize())
diff --git a/jwe/jwe.go b/jwe/jwe.go
index 7c2905a0..ae1b8e3a 100644
--- a/jwe/jwe.go
+++ b/jwe/jwe.go
@@ -19,6 +19,7 @@ import (
 	"github.com/lestrrat-go/jwx/v2/jwk"
 
 	"github.com/lestrrat-go/jwx/v2/jwa"
+	"github.com/lestrrat-go/jwx/v2/jwe/internal/aescbc"
 	"github.com/lestrrat-go/jwx/v2/jwe/internal/content_crypt"
 	"github.com/lestrrat-go/jwx/v2/jwe/internal/keyenc"
 	"github.com/lestrrat-go/jwx/v2/jwe/internal/keygen"
@@ -36,6 +37,8 @@ func Settings(options ...GlobalOption) {
 		switch option.Ident() {
 		case identMaxPBES2Count{}:
 			maxPBES2Count = option.Value().(int)
+		case identMaxBufferSize{}:
+			aescbc.SetMaxBufferSize(option.Value().(int64))
 		}
 	}
 }
diff --git a/jwe/options.yaml b/jwe/options.yaml
index bf7e0a01..2de7fdd1 100644
--- a/jwe/options.yaml
+++ b/jwe/options.yaml
@@ -138,4 +138,15 @@ options:
     comment: |
       WithMaxPBES2Count specifies the maximum number of PBES2 iterations
       to use when decrypting a message. If not specified, the default
-      value of 10,000 is used.
\ No newline at end of file
+      value of 10,000 is used.
+
+      This option has a global effect.
+  - ident: MaxBufferSize
+    interface: GlobalOption
+    argument_type: int64
+    comment: |
+      WithMaxBufferSize specifies the maximum buffer size for internal
+      calculations, such as when AES-CBC is performed. The default value is 256MB.
+      If set to an invalid value, the default value is used.
+
+      This option has a global effect.
\ No newline at end of file
diff --git a/jwe/options_gen.go b/jwe/options_gen.go
index b3de1320..3b74a8a9 100644
--- a/jwe/options_gen.go
+++ b/jwe/options_gen.go
@@ -129,6 +129,7 @@ type identFS struct{}
 type identKey struct{}
 type identKeyProvider struct{}
 type identKeyUsed struct{}
+type identMaxBufferSize struct{}
 type identMaxPBES2Count struct{}
 type identMergeProtectedHeaders struct{}
 type identMessage struct{}
@@ -166,6 +167,10 @@ func (identKeyUsed) String() string {
 	return "WithKeyUsed"
 }
 
+func (identMaxBufferSize) String() string {
+	return "WithMaxBufferSize"
+}
+
 func (identMaxPBES2Count) String() string {
 	return "WithMaxPBES2Count"
 }
@@ -245,9 +250,20 @@ func WithKeyUsed(v interface{}) DecryptOption {
 	return &decryptOption{option.New(identKeyUsed{}, v)}
 }
 
+// WithMaxBufferSize specifies the maximum buffer size for internal
+// calculations, such as when AES-CBC is performed. The default value is 256MB.
+// If set to an invalid value, the default value is used.
+//
+// This option has a global effect.
+func WithMaxBufferSize(v int64) GlobalOption {
+	return &globalOption{option.New(identMaxBufferSize{}, v)}
+}
+
 // WithMaxPBES2Count specifies the maximum number of PBES2 iterations
 // to use when decrypting a message. If not specified, the default
 // value of 10,000 is used.
+//
+// This option has a global effect.
 func WithMaxPBES2Count(v int) GlobalOption {
 	return &globalOption{option.New(identMaxPBES2Count{}, v)}
 }
diff --git a/jws/message.go b/jws/message.go
index adec8445..dca5dfeb 100644
--- a/jws/message.go
+++ b/jws/message.go
@@ -278,6 +278,11 @@ func (m *Message) UnmarshalJSON(buf []byte) error {
 			}
 			sig.SetDecodeCtx(nil)
 
+			if sig.protected == nil {
+				// Instead of barfing on a nil protected header, use an empty header
+				sig.protected = NewHeaders()
+			}
+
 			if i == 0 {
 				if !getB64Value(sig.protected) {
 					b64 = false
@@ -313,6 +318,11 @@ func (m *Message) UnmarshalJSON(buf []byte) error {
 			sig.protected = prt
 		}
 
+		if sig.protected == nil {
+			// Instead of barfing on a nil protected header, use an empty header
+			sig.protected = NewHeaders()
+		}
+
 		decoded, err := base64.DecodeString(*mup.Signature)
 		if err != nil {
 			return fmt.Errorf(`failed to base64 decode flattened signature: %w`, err)
diff --git a/jwt/openid/birthdate.go b/jwt/openid/birthdate.go
index c356d7f0..a193b403 100644
--- a/jwt/openid/birthdate.go
+++ b/jwt/openid/birthdate.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"math"
 	"regexp"
 	"strconv"
 
@@ -57,9 +58,22 @@ func (b *BirthdateClaim) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-func tointptr(v int64) *int {
-	i := int(v)
-	return &i
+var intSize int
+
+func init() {
+	switch math.MaxInt {
+	case math.MaxInt16:
+		intSize = 16
+	case math.MaxInt32:
+		intSize = 32
+	case math.MaxInt64:
+		intSize = 64
+	}
+}
+
+func parseBirthdayInt(s string) int {
+	i, _ := strconv.ParseInt(s, 10, intSize)
+	return int(i)
 }
 
 var birthdateRx = regexp.MustCompile(`^(\d{4})-(\d{2})-(\d{2})$`)
@@ -100,23 +114,23 @@ func (b *BirthdateClaim) Accept(v interface{}) error {
 		// we can assume that strconv.ParseInt always succeeds.
 		// strconv.ParseInt (and strconv.ParseUint that it uses internally)
 		// only returns range errors, so we should be safe.
-		year, _ := strconv.ParseInt(v[indices[2]:indices[3]], 10, 64)
+		year := parseBirthdayInt(v[indices[2]:indices[3]])
 		if year <= 0 {
 			return fmt.Errorf(`failed to parse birthdate year`)
 		}
-		tmp.year = tointptr(year)
+		tmp.year = &year
 
-		month, _ := strconv.ParseInt(v[indices[4]:indices[5]], 10, 64)
+		month := parseBirthdayInt(v[indices[4]:indices[5]])
 		if month <= 0 {
 			return fmt.Errorf(`failed to parse birthdate month`)
 		}
-		tmp.month = tointptr(month)
+		tmp.month = &month
 
-		day, _ := strconv.ParseInt(v[indices[6]:indices[7]], 10, 64)
+		day := parseBirthdayInt(v[indices[6]:indices[7]])
 		if day <= 0 {
 			return fmt.Errorf(`failed to parse birthdate day`)
 		}
-		tmp.day = tointptr(day)
+		tmp.day = &day
 
 		*b = tmp
 		return nil


Test patch:
diff --git a/jwe/jwe_test.go b/jwe/jwe_test.go
index 9559abcd..5f9a3bcb 100644
--- a/jwe/jwe_test.go
+++ b/jwe/jwe_test.go
@@ -959,3 +959,15 @@ func TestGHSA_7f9x_gw85_8grf(t *testing.T) {
 		}
 	}
 }
+
+func TestMaxBufferSize(t *testing.T) {
+	// NOTE: This has GLOBAL EFFECT
+	jwe.Settings(jwe.WithMaxBufferSize(1))
+	defer jwe.Settings(jwe.WithMaxBufferSize(0))
+
+	key, err := jwxtest.GenerateRsaJwk()
+	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
+
+	_, err = jwe.Encrypt([]byte("Lorem Ipsum"), jwe.WithContentEncryption(jwa.A128CBC_HS256), jwe.WithKey(jwa.RSA_OAEP, key))
+	require.Error(t, err, `jwe.Encrypt should fail`)
+}
diff --git a/jwe/options_gen_test.go b/jwe/options_gen_test.go
index d36b9765..b58d2362 100644
--- a/jwe/options_gen_test.go
+++ b/jwe/options_gen_test.go
@@ -16,6 +16,7 @@ func TestOptionIdent(t *testing.T) {
 	require.Equal(t, "WithKey", identKey{}.String())
 	require.Equal(t, "WithKeyProvider", identKeyProvider{}.String())
 	require.Equal(t, "WithKeyUsed", identKeyUsed{}.String())
+	require.Equal(t, "WithMaxBufferSize", identMaxBufferSize{}.String())
 	require.Equal(t, "WithMaxPBES2Count", identMaxPBES2Count{}.String())
 	require.Equal(t, "WithMergeProtectedHeaders", identMergeProtectedHeaders{}.String())
 	require.Equal(t, "WithMessage", identMessage{}.String())
diff --git a/jws/jws_test.go b/jws/jws_test.go
index d615ec37..04fdb9d9 100644
--- a/jws/jws_test.go
+++ b/jws/jws_test.go
@@ -1835,3 +1835,55 @@ func TestValidateKey(t *testing.T) {
 	_, err = jws.Verify(signed, jws.WithKey(jwa.RS256, pubKey), jws.WithValidateKey(true))
 	require.NoError(t, err, `jws.Verify should succeed`)
 }
+
+func TestEmptyProtectedField(t *testing.T) {
+	// MEMO: this was the only test case from the original report
+	// This passes. It should produce an invalid JWS message, but
+	// that's not `jws.Parse`'s problem.
+	_, err := jws.Parse([]byte(`{"signature": ""}`))
+	require.NoError(t, err, `jws.Parse should fail`)
+
+	// Also test that non-flattened serialization passes.
+	_, err = jws.Parse([]byte(`{"signatures": [{}]}`))
+	require.NoError(t, err, `jws.Parse should fail`)
+
+	// MEMO: rest of the cases are present to be extra pedantic about it
+
+	privKey, err := jwxtest.GenerateRsaJwk()
+	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
+
+	// This fails. `jws.Parse` works, but the subsequent verification
+	// workflow fails to verify anything without the presence of a signature or
+	// a protected header.
+	_, err = jws.Verify([]byte(`{"signature": ""}`), jws.WithKey(jwa.RS256, privKey))
+	require.Error(t, err, `jws.Parse should fail`)
+
+	// Create a valid signatre.
+	signed, err := jws.Sign([]byte("Lorem Ipsum"), jws.WithKey(jwa.RS256, privKey))
+	require.NoError(t, err, `jws.Sign should succeed`)
+
+	_, payload, signature, err := jws.SplitCompact(signed)
+	require.NoError(t, err, `jws.SplitCompact should succeed`)
+
+	// This fails as well. we have a valid signature and a valid
+	// key to verify it, but no protected headers
+	_, err = jws.Verify(
+		[]byte(fmt.Sprintf(`{"signature": "%s"}`, signature)),
+		jws.WithKey(jwa.RS256, privKey),
+	)
+	require.Error(t, err, `jws.Verify should fail`)
+
+	// Test for cases when we have an incomplete compact form JWS
+	var buf bytes.Buffer
+	buf.WriteRune('.')
+	buf.Write(payload)
+	buf.WriteRune('.')
+	buf.Write(signature)
+	invalidMessage := buf.Bytes()
+
+	// This is an error because the format is simply wrong.
+	// Whereas in the other JSON-based JWS's case the lack of protected field
+	// is not a SYNTAX error, this one is, and therefore we barf.
+	_, err = jws.Parse(invalidMessage)
+	require.Error(t, err, `jws.Parse should fail`)
+}