Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signature verification does not work when the token was encoded with whitespace #109

Closed
jshayes opened this issue Oct 31, 2016 · 1 comment

Comments

@jshayes
Copy link
Contributor

jshayes commented Oct 31, 2016

In RFC 7519 Section 7.1 it mentions

Create a JWT Claims Set containing the desired claims. Note that
whitespace is explicitly allowed in the representation and no
canonicalization need be performed before encoding.

Additionally, in RFC 7515 Section 3 it mentions

JWS represents digitally signed or MACed content using JSON data
structures and base64url encoding. These JSON data structures MAY
contain whitespace and/or line breaks before or after any JSON values
or structural characters, in accordance with Section 2 of RFC 7159
[RFC7159].

However, when generating a token with whitespace or line breaks in the JSON, the token does not pass the verification. For example, Example 1 below fails verification, whereas Example 2 passes verification.

Example 1
$header = '{
    "alg": "RS256"
}';

$payload = '{
    "a": "b"
}';

$encoder = new Base64UrlSafeEncoder();
$token = sprintf('%s.%s', $encoder->encode($header), $encoder->encode($payload));
$signer = new RS256();

$privateKey = openssl_pkey_get_private('path/to/private/key');
$signature = $encoder->encode($signer->sign($token, $privateKey));
$jwsToken = sprintf('%s.%s', $token, $signature);

$jws = JWS::load($jwsToken);
$publicKey = openssl_pkey_get_public('path/to/public/key');

$jws->verify($publicKey); // Returns false
Example 2
$header = '{"alg":"RS256"}';
$payload = '{"a":"b"}';

$encoder = new Base64UrlSafeEncoder();
$token = sprintf('%s.%s', $encoder->encode($header), $encoder->encode($payload));
$signer = new RS256();

$privateKey = openssl_pkey_get_private('path/to/private/key');
$signature = $encoder->encode($signer->sign($token, $privateKey));
$jwsToken = sprintf('%s.%s', $token, $signature);

$jws = JWS::load($jwsToken);
$publicKey = openssl_pkey_get_public('path/to/public/key');

$jws->verify($publicKey); // Returns true

It looks like the verify method takes the decoded header and payload arrays, JSON encodes them, then base64 encodes them. It then uses these values to generate the input that will be checked against the signature. However, since it decodes the token, then re-encodes it, the formatting is lost and the resulting signature is different.

Maybe it should take the original header and payload and use that to check against the signature, so that any formatting changes don't impact the verification step.

@odino
Copy link
Contributor

odino commented Nov 1, 2016

hey @jshayes thanks for the catch! Would you be able to send a PR for this fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants