- attached positive.png
Fail to verify a manipulated token
Hi hello,
I created below code just based on the example code from the homepage, just trying to learn how to verify a token with public jwk or public key. While doing that i ran into something weird: even if i added one charactor at the end of the signature of the token, the token can still pass verification; if added more than one character, the verification is doing fine.
Tried with below scenarios:
(1)Any length of chars added at the beginning or in the middle of the signature, the verification is working fine
(2)One char added at the end of the signature, the verification is failing, the modified token can still pass verification
(3)More than one char added at the end of the signature, the verification is working fine
(4)Any length of chars added in header section or payload section at any position, the verification is working fine
The code is as below:
package token.jwt;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.*;
import com.nimbusds.jwt.SignedJWT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class Test {
public static void main(String[] args) throws Exception {
// Generate an EC key pair
ECKey ecJWK = new ECKeyGenerator(Curve.P_256)
.keyID("123")
.generate();
ECKey ecPublicJWK = ecJWK.toPublicJWK();
// Create the EC signer
JWSSigner signer = new ECDSASigner(ecJWK);
// Creates the JWS object with payload
JWSObject jwsObject = new JWSObject(
new JWSHeader.Builder(JWSAlgorithm.ES256).keyID(ecJWK.getKeyID()).build(),
new Payload("Elliptic cure"));
// Compute the EC signature
jwsObject.sign(signer);
// Serialize the JWS to compact form
String s = jwsObject.serialize();
// Manipulated the original token and use it later
SignedJWT jwt = SignedJWT.parse(s + "X");
// The recipient creates a verifier with the public EC key
JWSVerifier verifier = new ECDSAVerifier(ecPublicJWK);
// Verify the EC signature of the manipulated token
assertTrue("ES256 signature verified", jwt.verify(verifier));
assertEquals("Elliptic cure", jwt.getPayload().toString());
}
}
And i am using version 5.4.1
Not sure if i missed anything or miss-understood anything.
Any suggestions on how to workaround this would be appreciated!
So many thanks,
leonL
Comments (12)
-
reporter -
reporter - attached negative.png
Manipulated token should not be verified with the public key
-
reporter - edited description
-
This is prob related to the ECDSA signature format in JWS, which may require padding of 1char to get the S and R sig vals of equals length, but then this padding is ignored when fed into the Java crypto engine.
https://bitbucket.org/connect2id/nimbus-jose-jwt/issues/315/ecdsatranscodesignaturetoder-ignores-the
-
reporter Would you have any idea how to workaround this?
Thanks!
-
Hi Leon,
What you witnessed is a case when a codec can allow for a trailing byte without affecting the underlying encoded bytes.
For the ESxxx verification there are two conversions: from 1) BASE64URL -> 2) concat byte arrays padded to same length -> 3) DER encoding.
I added a quick check to reject ESxxx sigs which length doesn’t match the expected for the alg (for ES256 this is 64 bytes for instance). This doesn’t change the DER encoding, but it does change the concatenated byte arrays length to 65 and can be detected.
Commit: d522806
Note, for the ES384 and ES512 algs adding an extra char to the sig BASE64URL cannot be detected. I suppose this will scare you If you take the sig BASE64URL of ES384 and get its byte array, then add an extra char and repeat, the decoded byte arrays will be identical. This is simply the nature of the BASE64 codec :)
test ->
This has come up in other libs:
Bug or question: Altering last meaningful character in base64 string doesn't change decoded outcome
#65 -
Issue
#315was marked as a duplicate of this issue. -
- changed status to resolved
Part of 9.4.2.
-
reporter Hi Vladimir,
So many thanks for the quick diagnostics! i ll try it
Thanks,
Leon
-
reporter And regarding “Note, for the ES384 and ES512 algs adding an extra char to the sig BASE64URL cannot be detected. I suppose this will scare you If you take the sig BASE64URL of ES384 and get its byte array, then add an extra char and repeat, the decoded byte arrays will be identical. This is simply the nature of the BASE64 codec :)“
Actually i noticed these during the investigation, just not so sure whether this is possible for any form of attacks. Now as i understand this doesnt seem to be a security issue since the header and payload can never be manipulated plus adding any length of extra to another position in the BASE64URL signature will also break the verification, is it correct?
Thanks again!
-Leon
-
Here is the explanation you’re looking for:
-
reporter Thanks again!
- Log in to comment
Original token can be verified with public key