Repository: lestrrat-go/jwx (go)

Issue:
Header setter error handling
Protocol header setter returns an error, but ignores it in multiple places. I found it by https://github.com/golangci/golangci-lint.

If we should always do error handling, I will create a pull request to add error handling. If error handling need not necessary, please tell me what is the difference between need error handling or not?


Pull request description:
Sonatard fix error
fixes #164
closes #177

Patch:
diff --git a/.gitignore b/.gitignore
index 7e31767f..f4c8ed8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,6 @@ _testmain.go
 
 coverage.out
 go.sum
+
+# I redirect my test output to files named "out" way too often
+out
diff --git a/.golangci.yml b/.golangci.yml
index 4737e92c..aabdc393 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -50,14 +50,22 @@ issues:
       text: "returns unexported type" # exported func XXX returns unexported type xxx which can be annoying to use
       linters:
         - golint
-    - path: /*.go
-      text: "don't use leading" # don't use leading k in Go names; const kKey should be key
+    - path: /main.go
       linters:
-        - golint
-    # fix it
-    - path: /*.go
+        - errcheck
+    - path: internal/codegen/codegen.go
+      linters:
+        - errcheck
+    - path: /*_test.go
       linters:
-        - errcheck # TODO: Error return value of `xxx` is not checked
+        - errcheck
+    # discuss
+    #- path: jwe/internal/aescbc/aescbc.go
+    #  linters:
+    #    - errcheck # TODO: Error return value of `xxx` is not checked
+    #- path: jwe/internal/keygen/keygen.go
+    #  linters:
+    #    - errcheck # TODO: Error return value of `xxx` is not checked
 
   # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
   max-issues-per-linter: 0
diff --git a/internal/concatkdf/concatkdf.go b/internal/concatkdf/concatkdf.go
index 5a89b55f..8247b416 100644
--- a/internal/concatkdf/concatkdf.go
+++ b/internal/concatkdf/concatkdf.go
@@ -6,6 +6,7 @@ import (
 	"hash"
 
 	"github.com/lestrrat-go/jwx/buffer"
+	"github.com/pkg/errors"
 )
 
 type KDF struct {
@@ -41,9 +42,15 @@ func (k *KDF) Read(buf []byte) (int, error) {
 	for len(buf) > len(k.buf) {
 		h.Reset()
 
-		binary.Write(h, binary.BigEndian, k.round)
-		h.Write(k.z)
-		h.Write(k.otherinfo)
+		if err := binary.Write(h, binary.BigEndian, k.round); err != nil {
+			return 0, errors.Wrap(err, "failed to write round using kdf")
+		}
+		if _, err := h.Write(k.z); err != nil {
+			return 0, errors.Wrap(err, "failed to write z using kdf")
+		}
+		if _, err := h.Write(k.otherinfo); err != nil {
+			return 0, errors.Wrap(err, "failed to write other info using kdf")
+		}
 
 		k.buf = append(k.buf, h.Sum(nil)...)
 		k.round++
diff --git a/jwe/encrypt.go b/jwe/encrypt.go
index bf998942..96d2f6ac 100644
--- a/jwe/encrypt.go
+++ b/jwe/encrypt.go
@@ -41,7 +41,9 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 	}
 
 	protected := NewHeaders()
-	protected.Set(ContentEncryptionKey, e.contentEncrypter.Algorithm())
+	if err := protected.Set(ContentEncryptionKey, e.contentEncrypter.Algorithm()); err != nil {
+		return nil, errors.Wrap(err, "failed to set enc in protected header")
+	}
 
 	// In JWE, multiple recipients may exist -- they receive an
 	// encrypted version of the CEK, using their key encryption
@@ -49,9 +51,13 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 	recipients := make([]Recipient, len(e.keyEncrypters))
 	for i, enc := range e.keyEncrypters {
 		r := NewRecipient()
-		r.Headers().Set(AlgorithmKey, enc.Algorithm())
+		if err := r.Headers().Set(AlgorithmKey, enc.Algorithm()); err != nil {
+			return nil, errors.Wrap(err, "failed to set header")
+		}
 		if v := enc.KeyID(); v != "" {
-			r.Headers().Set(KeyIDKey, v)
+			if err := r.Headers().Set(KeyIDKey, v); err != nil {
+				return nil, errors.Wrap(err, "failed to set header")
+			}
 		}
 		enckey, err := enc.Encrypt(cek)
 		if err != nil {
@@ -60,9 +66,13 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 			}
 			return nil, errors.Wrap(err, `failed to encrypt key`)
 		}
-		r.SetEncryptedKey(enckey.Bytes())
+		if err := r.SetEncryptedKey(enckey.Bytes()); err != nil {
+			return nil, errors.Wrap(err, "failed to set encrypted key")
+		}
 		if hp, ok := enckey.(populater); ok {
-			hp.Populate(r.Headers())
+			if err := hp.Populate(r.Headers()); err != nil {
+				return nil, errors.Wrap(err, "failed to populate")
+			}
 		}
 		if debug.Enabled {
 			debug.Printf("Encrypt: encrypted_key = %x (%d)", enckey.Bytes(), len(enckey.Bytes()))
@@ -103,7 +113,9 @@ func (e encryptCtx) Encrypt(plaintext []byte) (*Message, error) {
 	}
 
 	msg := NewMessage()
-	msg.authenticatedData.Base64Decode(aad)
+	if err := msg.authenticatedData.Base64Decode(aad); err != nil {
+		return nil, errors.Wrap(err, "failed to decode base64")
+	}
 	msg.cipherText = ciphertext
 	msg.initializationVector = iv
 	msg.protectedHeaders = protected
diff --git a/jwe/headers_gen.go b/jwe/headers_gen.go
index 4b31f176..bc89f0c6 100644
--- a/jwe/headers_gen.go
+++ b/jwe/headers_gen.go
@@ -57,6 +57,7 @@ type Headers interface {
 	AsMap(ctx context.Context) (map[string]interface{}, error)
 	Get(string) (interface{}, bool)
 	Set(string, interface{}) error
+	Remove(string) error
 	Encode() ([]byte, error)
 	Decode([]byte) error
 }
@@ -389,6 +390,9 @@ func (h *stdHeaders) Set(name string, value interface{}) error {
 		return errors.Errorf(`invalid value for %s key: %T`, CompressionKey, value)
 	case ContentEncryptionKey:
 		if v, ok := value.(jwa.ContentEncryptionAlgorithm); ok {
+			if v == "" {
+				return errors.New(`"enc" field cannot be an empty string`)
+			}
 			h.contentEncryption = &v
 			return nil
 		}
@@ -468,6 +472,46 @@ func (h *stdHeaders) Set(name string, value interface{}) error {
 	return nil
 }
 
+func (h *stdHeaders) Remove(key string) error {
+	switch key {
+	case AgreementPartyUInfoKey:
+		h.agreementPartyUInfo = nil
+	case AgreementPartyVInfoKey:
+		h.agreementPartyVInfo = nil
+	case AlgorithmKey:
+		h.algorithm = nil
+	case CompressionKey:
+		h.compression = nil
+	case ContentEncryptionKey:
+		h.contentEncryption = nil
+	case ContentTypeKey:
+		h.contentType = nil
+	case CriticalKey:
+		h.critical = nil
+	case EphemeralPublicKeyKey:
+		h.ephemeralPublicKey = nil
+	case JWKKey:
+		h.jwk = nil
+	case JWKSetURLKey:
+		h.jwkSetURL = nil
+	case KeyIDKey:
+		h.keyID = nil
+	case TypeKey:
+		h.typ = nil
+	case X509CertChainKey:
+		h.x509CertChain = nil
+	case X509CertThumbprintKey:
+		h.x509CertThumbprint = nil
+	case X509CertThumbprintS256Key:
+		h.x509CertThumbprintS256 = nil
+	case X509URLKey:
+		h.x509URL = nil
+	default:
+		delete(h.privateParams, key)
+	}
+	return nil
+}
+
 func (h *stdHeaders) UnmarshalJSON(buf []byte) error {
 	var proxy standardHeadersMarshalProxy
 	if err := json.Unmarshal(buf, &proxy); err != nil {
diff --git a/jwe/interface.go b/jwe/interface.go
index 00774f84..b8455829 100644
--- a/jwe/interface.go
+++ b/jwe/interface.go
@@ -54,7 +54,7 @@ type encryptCtx struct {
 // populater is an interface for things that may modify the
 // JWE header. e.g. ByteWithECPrivateKey
 type populater interface {
-	Populate(keygen.Setter)
+	Populate(keygen.Setter) error
 }
 
 type Visitor = iter.MapVisitor
diff --git a/jwe/internal/aescbc/aescbc.go b/jwe/internal/aescbc/aescbc.go
index 4b33d79e..8db5eeea 100644
--- a/jwe/internal/aescbc/aescbc.go
+++ b/jwe/internal/aescbc/aescbc.go
@@ -77,7 +77,7 @@ func (c Hmac) Overhead() int {
 	return c.blockCipher.BlockSize() + c.tagsize
 }
 
-func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) []byte {
+func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) ([]byte, error) {
 	if debug.Enabled {
 		debug.Printf("ComputeAuthTag: aad        = %x (%d)\n", aad, len(aad))
 		debug.Printf("ComputeAuthTag: ciphertext = %x (%d)\n", ciphertext, len(ciphertext))
@@ -93,13 +93,15 @@ func (c Hmac) ComputeAuthTag(aad, nonce, ciphertext []byte) []byte {
 	binary.BigEndian.PutUint64(buf[n:], uint64(len(aad)*8))
 
 	h := hmac.New(c.hash, c.integrityKey)
-	h.Write(buf)
+	if _, err := h.Write(buf); err != nil {
+		return nil, errors.Wrap(err, "failed to write ComputeAuthTag using Hmac")
+	}
 	s := h.Sum(nil)
 	if debug.Enabled {
 		debug.Printf("ComputeAuthTag: buf        = %x (%d)\n", buf, len(buf))
 		debug.Printf("ComputeAuthTag: computed   = %x (%d)\n", s[:c.keysize], len(s[:c.keysize]))
 	}
-	return s[:c.tagsize]
+	return s[:c.tagsize], nil
 }
 
 func ensureSize(dst []byte, n int) []byte {
@@ -125,7 +127,12 @@ func (c Hmac) Seal(dst, nonce, plaintext, data []byte) []byte {
 	cbc := cipher.NewCBCEncrypter(c.blockCipher, nonce)
 	cbc.CryptBlocks(ciphertext, ciphertext)
 
-	authtag := c.ComputeAuthTag(data, nonce, ciphertext)
+	authtag, err := c.ComputeAuthTag(data, nonce, ciphertext)
+	if err != nil {
+		// Hmac implements cipher.AEAD interface. Seal can't return error.
+		// But currently it never reach here because of Hmac.ComputeAuthTag doesn't return error.
+		panic(fmt.Errorf("failed to seal on hmac: %v", err))
+	}
 
 	retlen := len(dst) + len(ciphertext) + len(authtag)
 
@@ -159,7 +166,11 @@ func (c Hmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
 	tag := ciphertext[tagOffset:]
 	ciphertext = ciphertext[:tagOffset]
 
-	expectedTag := c.ComputeAuthTag(data, nonce, ciphertext)
+	expectedTag, err := c.ComputeAuthTag(data, nonce, ciphertext)
+	if err != nil {
+		return nil, errors.Wrap(err, `failed to compute auth tag`)
+	}
+
 	if subtle.ConstantTimeCompare(expectedTag, tag) != 1 {
 		if debug.Enabled {
 			debug.Printf("provided tag = %x\n", tag)
diff --git a/jwe/internal/cmd/genheader/main.go b/jwe/internal/cmd/genheader/main.go
index a6e4daf4..7479afc1 100644
--- a/jwe/internal/cmd/genheader/main.go
+++ b/jwe/internal/cmd/genheader/main.go
@@ -259,6 +259,7 @@ func generateHeaders() error {
 	// These are used to access a single element by key name
 	fmt.Fprintf(&buf, "\nGet(string) (interface{}, bool)")
 	fmt.Fprintf(&buf, "\nSet(string, interface{}) error")
+	fmt.Fprintf(&buf, "\nRemove(string) error")
 
 	// These are used to deal with encoded headers
 	fmt.Fprintf(&buf, "\nEncode() ([]byte, error)")
@@ -369,6 +370,13 @@ func generateHeaders() error {
 			fmt.Fprintf(&buf, "\nreturn nil")
 		} else {
 			fmt.Fprintf(&buf, "\nif v, ok := value.(%s); ok {", f.typ)
+			if f.name == "contentEncryption" {
+				// check for non-empty string, because empty content encryption is just baaaaaad
+				fmt.Fprintf(&buf, "\nif v == \"\" {")
+				fmt.Fprintf(&buf, "\nreturn errors.New(`%#v field cannot be an empty string`)", f.key)
+				fmt.Fprintf(&buf, "\n}")
+			}
+
 			if fieldStorageTypeIsIndirect(f.typ) {
 				fmt.Fprintf(&buf, "\nh.%s = &v", f.name)
 			} else {
@@ -388,6 +396,18 @@ func generateHeaders() error {
 	fmt.Fprintf(&buf, "\nreturn nil")
 	fmt.Fprintf(&buf, "\n}") // end func (h *stdHeaders) Set(name string, value interface{})
 
+	fmt.Fprintf(&buf, "\n\nfunc (h *stdHeaders) Remove(key string) error {")
+	fmt.Fprintf(&buf, "\nswitch key {")
+	for _, f := range fields {
+		fmt.Fprintf(&buf, "\ncase %sKey:", f.method)
+		fmt.Fprintf(&buf, "\nh.%s = nil", f.name)
+	}
+	fmt.Fprintf(&buf, "\ndefault:")
+	fmt.Fprintf(&buf, "\ndelete(h.privateParams, key)")
+	fmt.Fprintf(&buf, "\n}")
+	fmt.Fprintf(&buf, "\nreturn nil") // currently unused, but who knows
+	fmt.Fprintf(&buf, "\n}")
+
 	fmt.Fprintf(&buf, "\n\nfunc (h *stdHeaders) UnmarshalJSON(buf []byte) error {")
 	fmt.Fprintf(&buf, "\nvar proxy standardHeadersMarshalProxy")
 	fmt.Fprintf(&buf, "\nif err := json.Unmarshal(buf, &proxy); err != nil {")
diff --git a/jwe/internal/keyenc/keyenc.go b/jwe/internal/keyenc/keyenc.go
index 590357da..6ee1871d 100644
--- a/jwe/internal/keyenc/keyenc.go
+++ b/jwe/internal/keyenc/keyenc.go
@@ -155,7 +155,9 @@ func (kw ECDHESDecrypt) Decrypt(enckey []byte) ([]byte, error) {
 	z, _ := privkey.PublicKey.Curve.ScalarMult(pubkey.X, pubkey.Y, privkey.D.Bytes())
 	kdf := concatkdf.New(crypto.SHA256, []byte(kw.algorithm.String()), z.Bytes(), kw.apu, kw.apv, pubinfo, []byte{})
 	kek := make([]byte, keysize)
-	kdf.Read(kek)
+	if _, err := kdf.Read(kek); err != nil {
+		return nil, errors.Wrap(err, "failed to read kdf")
+	}
 
 	block, err := aes.NewCipher(kek)
 	if err != nil {
diff --git a/jwe/internal/keygen/keygen.go b/jwe/internal/keygen/keygen.go
index ac120068..394662d8 100644
--- a/jwe/internal/keygen/keygen.go
+++ b/jwe/internal/keygen/keygen.go
@@ -91,7 +91,9 @@ func (g Ecdhes) Generate() (ByteSource, error) {
 	z, _ := priv.PublicKey.Curve.ScalarMult(g.pubkey.X, g.pubkey.Y, priv.D.Bytes())
 	kdf := concatkdf.New(crypto.SHA256, []byte(g.algorithm.String()), z.Bytes(), []byte{}, []byte{}, pubinfo, []byte{})
 	kek := make([]byte, g.keysize)
-	kdf.Read(kek)
+	if _, err := kdf.Read(kek); err != nil {
+		return nil, errors.Wrap(err, "failed to read kdf")
+	}
 
 	return ByteWithECPrivateKey{
 		PrivateKey: priv,
@@ -101,9 +103,14 @@ func (g Ecdhes) Generate() (ByteSource, error) {
 
 // HeaderPopulate populates the header with the required EC-DSA public key
 // information ('epk' key)
-func (k ByteWithECPrivateKey) Populate(h Setter) {
+func (k ByteWithECPrivateKey) Populate(h Setter) error {
 	key, err := jwk.New(&k.PrivateKey.PublicKey)
-	if err == nil {
-		h.Set("epk", key)
+	if err != nil {
+		return errors.Wrap(err, "failed to create JWK")
+	}
+
+	if err := h.Set("epk", key); err != nil {
+		return errors.Wrap(err, "failed to write header")
 	}
+	return nil
 }
diff --git a/jwe/jwe.go b/jwe/jwe.go
index a5592697..06acc63e 100644
--- a/jwe/jwe.go
+++ b/jwe/jwe.go
@@ -199,8 +199,13 @@ func parseCompact(buf []byte) (*Message, error) {
 	// We need the protected header to contain the content encryption
 	// algorithm. XXX probably other headers need to go there too
 	protected := NewHeaders()
-	protected.Set(ContentEncryptionKey, hdr.ContentEncryption())
-	hdr.Set(ContentEncryptionKey, "")
+	if err := protected.Set(ContentEncryptionKey, hdr.ContentEncryption()); err != nil {
+		return nil, errors.Wrapf(err, "failed to set %#v in protected header", ContentEncryptionKey)
+	}
+
+	if err := hdr.Remove(ContentEncryptionKey); err != nil {
+		return nil, errors.Wrapf(err, "failed to remove %#v from public header", ContentEncryptionKey)
+	}
 
 	var enckeybuf buffer.Buffer
 	if err := enckeybuf.Base64Decode(parts[1]); err != nil {
diff --git a/jwk/ecdsa.go b/jwk/ecdsa.go
index 274518b3..b211bce0 100644
--- a/jwk/ecdsa.go
+++ b/jwk/ecdsa.go
@@ -37,11 +37,17 @@ func (k *ecdsaPublicKey) FromRaw(rawKey *ecdsa.PublicKey) error {
 	k.y = rawKey.Y.Bytes()
 	switch rawKey.Curve {
 	case elliptic.P256():
-		k.Set(ecdsaCrvKey, jwa.P256)
+		if err := k.Set(ecdsaCrvKey, jwa.P256); err != nil {
+			return errors.Wrap(err, `failed to set header`)
+		}
 	case elliptic.P384():
-		k.Set(ecdsaCrvKey, jwa.P384)
+		if err := k.Set(ecdsaCrvKey, jwa.P384); err != nil {
+			return errors.Wrap(err, `failed to set header`)
+		}
 	case elliptic.P521():
-		k.Set(ecdsaCrvKey, jwa.P521)
+		if err := k.Set(ecdsaCrvKey, jwa.P521); err != nil {
+			return errors.Wrap(err, `failed to set header`)
+		}
 	default:
 		return errors.Errorf(`invalid elliptic curve %s`, rawKey.Curve)
 	}
@@ -54,11 +60,17 @@ func (k *ecdsaPrivateKey) FromRaw(rawKey *ecdsa.PrivateKey) error {
 	k.y = rawKey.Y.Bytes()
 	switch rawKey.Curve {
 	case elliptic.P256():
-		k.Set(ecdsaCrvKey, jwa.P256)
+		if err := k.Set(ecdsaCrvKey, jwa.P256); err != nil {
+			return errors.Wrap(err, "failed to write header")
+		}
 	case elliptic.P384():
-		k.Set(ecdsaCrvKey, jwa.P384)
+		if err := k.Set(ecdsaCrvKey, jwa.P384); err != nil {
+			return errors.Wrap(err, "failed to write header")
+		}
 	case elliptic.P521():
-		k.Set(ecdsaCrvKey, jwa.P521)
+		if err := k.Set(ecdsaCrvKey, jwa.P521); err != nil {
+			return errors.Wrap(err, "failed to write header")
+		}
 	default:
 		return errors.Errorf(`invalid elliptic curve %s`, rawKey.Curve)
 	}
diff --git a/jwk/rsa.go b/jwk/rsa.go
index 35ba86aa..7b85fce6 100644
--- a/jwk/rsa.go
+++ b/jwk/rsa.go
@@ -182,6 +182,8 @@ func rsaThumbprint(hash crypto.Hash, key *rsa.PublicKey) ([]byte, error) {
 	buf.WriteString(`"}`)
 
 	h := hash.New()
-	buf.WriteTo(h)
+	if _, err := buf.WriteTo(h); err != nil {
+		return nil, errors.Wrap(err, "failed to write rsaThumbprint")
+	}
 	return h.Sum(nil), nil
 }
diff --git a/jws/jws.go b/jws/jws.go
index 54cff697..09d3e71c 100644
--- a/jws/jws.go
+++ b/jws/jws.go
@@ -97,7 +97,9 @@ func Sign(payload []byte, alg jwa.SignatureAlgorithm, key interface{}, options .
 		return nil, errors.Wrap(err, `failed to create signer`)
 	}
 
-	hdrs.Set(AlgorithmKey, signer.Algorithm())
+	if err := hdrs.Set(AlgorithmKey, signer.Algorithm()); err != nil {
+		return nil, errors.Wrap(err, `failed to set header`)
+	}
 
 	hdrbuf, err := json.Marshal(hdrs)
 	if err != nil {
@@ -215,7 +217,9 @@ func SignMulti(payload []byte, options ...Option) ([]byte, error) {
 			protected = NewHeaders()
 		}
 
-		protected.Set(AlgorithmKey, signer.Algorithm())
+		if err := protected.Set(AlgorithmKey, signer.Algorithm()); err != nil {
+			return nil, errors.Wrap(err, `failed to set header`)
+		}
 
 		hdrbuf, err := json.Marshal(protected)
 		if err != nil {
@@ -409,7 +413,10 @@ func Parse(src io.Reader) (m *Message, err error) {
 		}
 		if !unicode.IsSpace(r) {
 			first = r
-			rdr.UnreadRune()
+			if err := rdr.UnreadRune(); err != nil {
+				return nil, errors.Wrap(err, `failed to unread rune`)
+			}
+
 			break
 		}
 	}
diff --git a/jws/sign/ecdsa.go b/jws/sign/ecdsa.go
index db359d9f..74559c71 100644
--- a/jws/sign/ecdsa.go
+++ b/jws/sign/ecdsa.go
@@ -24,7 +24,7 @@ func init() {
 }
 
 func makeECDSASignFunc(hash crypto.Hash) ecdsaSignFunc {
-	return ecdsaSignFunc(func(payload []byte, key *ecdsa.PrivateKey) ([]byte, error) {
+	return func(payload []byte, key *ecdsa.PrivateKey) ([]byte, error) {
 		curveBits := key.Curve.Params().BitSize
 		keyBytes := curveBits / 8
 		// Curve bits do not need to be a multiple of 8.
@@ -32,7 +32,9 @@ func makeECDSASignFunc(hash crypto.Hash) ecdsaSignFunc {
 			keyBytes++
 		}
 		h := hash.New()
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return nil, errors.Wrap(err, "failed to write payload using ecdsa")
+		}
 		r, s, err := ecdsa.Sign(rand.Reader, key, h.Sum(nil))
 		if err != nil {
 			return nil, errors.Wrap(err, "failed to sign payload using ecdsa")
@@ -48,7 +50,7 @@ func makeECDSASignFunc(hash crypto.Hash) ecdsaSignFunc {
 
 		out := append(rBytesPadded, sBytesPadded...)
 		return out, nil
-	})
+	}
 }
 
 func newECDSA(alg jwa.SignatureAlgorithm) (*ECDSASigner, error) {
diff --git a/jws/sign/hmac.go b/jws/sign/hmac.go
index a5aea329..e8d620bf 100644
--- a/jws/sign/hmac.go
+++ b/jws/sign/hmac.go
@@ -37,11 +37,13 @@ func newHMAC(alg jwa.SignatureAlgorithm) (*HMACSigner, error) {
 }
 
 func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc {
-	return hmacSignFunc(func(payload []byte, key []byte) ([]byte, error) {
+	return func(payload []byte, key []byte) ([]byte, error) {
 		h := hmac.New(hfunc, key)
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return nil, errors.Wrap(err, "failed to write payload using hmac")
+		}
 		return h.Sum(nil), nil
-	})
+	}
 }
 
 func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm {
diff --git a/jws/sign/rsa.go b/jws/sign/rsa.go
index 31a7239e..eb410c72 100644
--- a/jws/sign/rsa.go
+++ b/jws/sign/rsa.go
@@ -48,21 +48,25 @@ func init() {
 }
 
 func makeSignPKCS1v15(hash crypto.Hash) rsaSignFunc {
-	return rsaSignFunc(func(payload []byte, key *rsa.PrivateKey) ([]byte, error) {
+	return func(payload []byte, key *rsa.PrivateKey) ([]byte, error) {
 		h := hash.New()
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return nil, errors.Wrap(err, "failed to write payload using SignPKCS1v15")
+		}
 		return rsa.SignPKCS1v15(rand.Reader, key, hash, h.Sum(nil))
-	})
+	}
 }
 
 func makeSignPSS(hash crypto.Hash) rsaSignFunc {
-	return rsaSignFunc(func(payload []byte, key *rsa.PrivateKey) ([]byte, error) {
+	return func(payload []byte, key *rsa.PrivateKey) ([]byte, error) {
 		h := hash.New()
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return nil, errors.Wrap(err, "failed to write payload using SignPSS")
+		}
 		return rsa.SignPSS(rand.Reader, key, hash, h.Sum(nil), &rsa.PSSOptions{
 			SaltLength: rsa.PSSSaltLengthAuto,
 		})
-	})
+	}
 }
 
 func newRSA(alg jwa.SignatureAlgorithm) (*RSASigner, error) {
diff --git a/jws/verify/ecdsa.go b/jws/verify/ecdsa.go
index 791e63d2..a5008bba 100644
--- a/jws/verify/ecdsa.go
+++ b/jws/verify/ecdsa.go
@@ -31,7 +31,9 @@ func makeECDSAVerifyFunc(hash crypto.Hash) ecdsaVerifyFunc {
 		s.SetBytes(signature[n:])
 
 		h := hash.New()
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return errors.Wrap(err, "failed to write payload using ecdsa")
+		}
 
 		if !ecdsa.Verify(key, h.Sum(nil), r, s) {
 			return errors.New(`failed to verify signature using ecdsa`)
diff --git a/jws/verify/rsa.go b/jws/verify/rsa.go
index 91b18f04..62dd8d86 100644
--- a/jws/verify/rsa.go
+++ b/jws/verify/rsa.go
@@ -47,19 +47,24 @@ func init() {
 }
 
 func makeVerifyPKCS1v15(hash crypto.Hash) rsaVerifyFunc {
-	return rsaVerifyFunc(func(payload, signature []byte, key *rsa.PublicKey) error {
+	return func(payload, signature []byte, key *rsa.PublicKey) error {
 		h := hash.New()
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return errors.Wrap(err, "failed to write payload using PKCS1v15")
+		}
+
 		return rsa.VerifyPKCS1v15(key, hash, h.Sum(nil), signature)
-	})
+	}
 }
 
 func makeVerifyPSS(hash crypto.Hash) rsaVerifyFunc {
-	return rsaVerifyFunc(func(payload, signature []byte, key *rsa.PublicKey) error {
+	return func(payload, signature []byte, key *rsa.PublicKey) error {
 		h := hash.New()
-		h.Write(payload)
+		if _, err := h.Write(payload); err != nil {
+			return errors.Wrap(err, "failed to write payload using PSS")
+		}
 		return rsa.VerifyPSS(key, hash, h.Sum(nil), signature, nil)
-	})
+	}
 }
 
 func newRSA(alg jwa.SignatureAlgorithm) (*RSAVerifier, error) {
diff --git a/jwt/openid/address.go b/jwt/openid/address.go
index 7c41642a..ccb8c751 100644
--- a/jwt/openid/address.go
+++ b/jwt/openid/address.go
@@ -182,7 +182,9 @@ func (t *AddressClaim) Accept(v interface{}) error {
 	switch v := v.(type) {
 	case map[string]interface{}:
 		for key, value := range v {
-			t.Set(key, value)
+			if err := t.Set(key, value); err != nil {
+				return errors.Wrap(err, `failed to set header`)
+			}
 		}
 		return nil
 	default:


Test patch:
diff --git a/jwe/internal/aescbc/aescbc_test.go b/jwe/internal/aescbc/aescbc_test.go
index 2e6f7b15..8989d9fc 100644
--- a/jwe/internal/aescbc/aescbc_test.go
+++ b/jwe/internal/aescbc/aescbc_test.go
@@ -36,6 +36,9 @@ func TestVectorsAESCBC128(t *testing.T) {
 		3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101}
 
 	enc, err := New(key, aes.NewCipher)
+	if !assert.NoError(t, err, "aescbc.New") {
+		return
+	}
 	out := enc.Seal(nil, nonce, plaintext, aad)
 	if !assert.NoError(t, err, "enc.Seal") {
 		return
diff --git a/jwe/jwe_test.go b/jwe/jwe_test.go
index 60b68e6e..49627aff 100644
--- a/jwe/jwe_test.go
+++ b/jwe/jwe_test.go
@@ -99,6 +99,15 @@ func TestParse_RSAES_OAEP_AES_GCM(t *testing.T) {
 		return
 	}
 
+	if !assert.Equal(t, 1, len(msg.Recipients()), "message recipients header length is 1") {
+		return
+	}
+
+	_, ok := msg.Recipients()[0].Headers().Get(jwe.ContentEncryptionKey)
+	if !assert.Equal(t, false, ok, "no content encryption key in message recipients header") {
+		return
+	}
+
 	plaintext, err := msg.Decrypt(jwa.RSA_OAEP, rawkey)
 	if !assert.NoError(t, err, "Decrypt message succeeded") {
 		return