Skip to content

Commit

Permalink
fix: handle Unencoded Payload (b64:false) with arbitrary buffer payloads
Browse files Browse the repository at this point in the history
fixes #57
  • Loading branch information
panva committed Dec 5, 2019
1 parent 749b2ac commit daabedc
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 4 deletions.
2 changes: 1 addition & 1 deletion lib/jws/serializers.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ generalSerializer.validate = (jws, recipients) => {
}

const isJSON = (input) => {
return isObject(input) && typeof input.payload === 'string'
return isObject(input) && (typeof input.payload === 'string' || Buffer.isBuffer(input.payload))
}

const isValidRecipient = (recipient) => {
Expand Down
15 changes: 13 additions & 2 deletions lib/jws/sign.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Sign {
payload = base64url.encode(payload)
} else if (Buffer.isBuffer(payload)) {
payload = base64url.encodeBuffer(payload)
i(this).binary = true
} else if (isObject(payload)) {
payload = base64url.JSON.encode(payload)
} else {
Expand Down Expand Up @@ -97,13 +98,23 @@ class Sign {
i(this).b64 = joseHeader.protected.b64
}
if (!joseHeader.protected.b64) {
i(this).payload = base64url.decode(i(this).payload)
if (i(this).binary) {
i(this).payload = base64url.decodeToBuffer(i(this).payload)
} else {
i(this).payload = base64url.decode(i(this).payload)
}
}
}

recipient.header = unprotectedHeader
recipient.protected = Object.keys(joseHeader.protected).length ? base64url.JSON.encode(joseHeader.protected) : ''
recipient.signature = base64url.encodeBuffer(sign(alg, key, Buffer.from(`${recipient.protected}.${i(this).payload}`)))

const toBeSigned = Buffer.concat([
Buffer.from(recipient.protected || ''),
Buffer.from('.'),
Buffer.isBuffer(i(this).payload) ? i(this).payload : Buffer.from(i(this).payload)
])
recipient.signature = base64url.encodeBuffer(sign(alg, key, toBeSigned))
}

/*
Expand Down
7 changes: 6 additions & 1 deletion lib/jws/verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], comp

check(key, 'verify', alg)

if (!verify(alg, key, Buffer.from([prot, payload].join('.')), base64url.decodeToBuffer(signature))) {
const toBeVerified = Buffer.concat([
Buffer.from(prot || ''),
Buffer.from('.'),
Buffer.isBuffer(payload) ? payload : Buffer.from(payload)
])
if (!verify(alg, key, toBeVerified, base64url.decodeToBuffer(signature))) {
throw new errors.JWSVerificationFailed()
}

Expand Down
8 changes: 8 additions & 0 deletions test/jws/b64.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const test = require('ava')

const { randomBytes } = require('crypto')
const { JWK, JWS, errors } = require('../..')

const k = JWK.asKey({
Expand All @@ -22,6 +23,13 @@ test('b64=false is supported for JWS', t => {
t.is(JWS.verify(FIXTURE, k, { crit: ['b64'] }), FIXTURE.payload)
})

test('b64=false with buffers', t => {
const payload = randomBytes(32)

This comment has been minimized.

Copy link
@davidlehn

davidlehn Dec 5, 2019

It would be good to also test specific deterministic inputs.

This comment has been minimized.

Copy link
@panva

panva Dec 5, 2019

Author Owner

feel free to propose a PR with more test cases!

const { payload: _, ...detached } = JWS.sign.flattened(payload, k, { alg: 'HS256', b64: false, crit: ['b64'] })

t.is(JWS.verify({ ...detached, payload }, k, { crit: ['b64'] }), payload)
})

test('b64=true is also allowed', t => {
const jws = JWS.sign.flattened('$.02', k, { alg: 'HS256', b64: true, crit: ['b64'] })
t.is(jws.payload, 'JC4wMg')
Expand Down

0 comments on commit daabedc

Please sign in to comment.