ucan-wg/ts-ucan

Check original encoded strings against the signature

matheus23 opened this issue · 0 comments

To verify the UCAN signature, at the moment we're decoding the base64 parts of the UCAN into JSON, then stringify that JSON back into base64 and then bytes, and then check those bytes against the signature.

This process is likely to be lossy in unexpected ways. JSON.stringify(JSON.parse(x)) === x doesn't hold for all values of x.

This results in some UCANs being rejected even though their signatures are correct.

Relevant code:

ts-ucan/src/token.ts

Lines 204 to 210 in 6a75d56

const encodedHeader = encodeHeader(ucan.header)
const encodedPayload = encodePayload(ucan.payload)
const data = uint8arrays.fromString(`${encodedHeader}.${encodedPayload}`)
const sig = uint8arrays.fromString(ucan.signature, 'base64urlpad')
const valid = await verifySignature(data, sig, ucan.payload.iss)

I think we should change the API somewhat to fix this issue:

async function checkSignature(string: encodedUcan): Promise<boolean>
function decode(string: encodedUcan): UCAN
async function validate(string: encodedUcan): Promise<UCAN> { // throws if invalid? Or just returns Result<>
  // ...
  ... = await checkSignature(encodedUcan)
  // ...
  const ucan = decode(encodedUcan)
  // ...
}