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

Add x5c and verify public key against x5c when extracting a public key from a JSON Web Key #24

Open
robotdan opened this issue Oct 15, 2020 · 6 comments
Assignees

Comments

@robotdan
Copy link
Member

robotdan commented Oct 15, 2020

Issue

Inbound thread from Nightwatch Cybersecurity Research

Nightwatch Cybersecurity Research <research@....>
It looks like the "x5c" field is not being used, while the RFC
dictates that "x5c" needs to verify the raw key materials:
https://tools.ietf.org/html/rfc7517#section-4.7

Nightwatch Cybersecurity Research <research@....>
Hi,

If the JWKS endpoint is compromised or the JWKS data is modified while
in transit by an MITM attacker (when the URL is non-HTTPS). Such an
attacker can choose to modify the public key information only and
leave the certificate alone, so an application verifying the
certificate will miss the fact that the public key doesn't match.

There is some discussion on the IETF list ot this affect:
https://mailarchive.ietf.org/arch/msg/jose/f_jo8sfQN6TqzkpmzgzzMb3_kEw/

Thanks

Solution

Add the x5c to the JSON Web Key when parsing a certificate, and when extracting a public key from a JSON Web key, attempt to verify the public key against the x5c if possible.

Solution notes

From what I can gather, a consumer of the JWKs may just use the certificate directly if available in the x5c parameter and not trust or parse the public key components.

However, if we also verify the response has not been modified by verifying the key components such as e, and n for RSA keys, or the x and y coordinates for an EC key, we should be able to detect when the public key represented by the JSON Web key does not match the x5c parameter.

With all that said, it seems to me if you are concerned about the thread of MITM when consuming JWKS, you should only accept JWKS from a TLS endpoint which has HSTS enabled. Or, only accept a JWK if it is published with the x5c and ignore the public key components in the JWK response.

If you were to be accepting a JSON Web Key from an endpoint that had been compromised by a MITM, it would seem to me the easier way to mess with someone is to remove the x5c parameter AND modify the public key components so it could not be verified. I do not know why you'd modify the public key components and NOT remove the x5c.

In any case, it doesn't hurt to perform some additional validation against the JSON Web Key to ensure the public key components match up with the certificate if found in the x5c parameter if we think it may help security some fashion.

@robotdan robotdan self-assigned this Oct 15, 2020
@robotdan
Copy link
Member Author

Commits:

fd761c6
4465240
ec26cb7

@nightwatchcyber
Copy link

Regarding the x5c material itself - it seems at the minimum, it would be nice to provide a feature to validate the certificate against the CAs known by the JVM

@robotdan
Copy link
Member Author

I can take a look at adding that capability.

@robotdan
Copy link
Member Author

robotdan commented Nov 6, 2020

Release 3.6.0 w/ validation for x5c. I'll keep this open to still look at adding certificate verification options.

@GokulMahajan20
Copy link

GokulMahajan20 commented Feb 16, 2022

Hello @robotdan

Came across this discussion while searching on the internet for the issue I am getting while trying to verify my Id Token.
I think you can help me with the issue so posting it here, I am sorry if this is not the correct place to ask about issues, I tried posting it on forums and stackoverflow but no help so far.

I am using fusionauth-jwt library to verify ID token signed by RSA SHA 256 key.
In my code below ,first trying to get public key using JWKS json and then trying to create a Verifier instance so that I can verify my id token.

List<JSONWebKey> keys = JSONWebKeySetHelper.retrieveKeysFromJWKS("http://localhost:9011/.well-known/jwks.json");

        Map<String, Verifier> publicKeyVerifiers = new HashMap<String,Verifier>();
        for (JSONWebKey key : keys) {
            String publicKey = key.x5c.get(0); //getting x5c element
            Verifier verifier = RSAVerifier.newVerifier(publicKey); // Creating RSA verifier instance where getting issue
            String kid = key.kid;
            publicKeyVerifiers.put(kid, verifier);
        }

JWT jwtDecoded = JWT.getDecoder().decode(idToken, publicKeyVerifiers);

Getting issue at the time of creating verifier instance because the x5c element contains Base64Encoded value and not the .pem format value which begins with "-----BEGIN"

Class "io.fusionauth.pem.PEMDecoder.java" expects "-----BEGIN" which is not present in key.x5c and hence throwing exception "throw new PEMDecoderException(new InvalidParameterException("Unexpected PEM Format"));

Screenshot of PEMDecoder.java

image

Please could you suggest how to fix it.
Thanks.

@robotdan
Copy link
Member Author

@GokulMahajan20 - it looks like we are expect the key to be PEM encoded. The x5c is not PEM encoded, it is just a base64 encoded version of the key. (mostly the same as PEM except no headers, and is not MIME encoded)

Could you just pass in the byte array instead?

String publicKey = key.x5c.get(0);
byte[] decoded = Base64.getDecoder().decode(publicKey);
Verifier verifier = RSAVerifier.newVerifier(decoded); // Creating RSA verifier instance where getting issue

Would that work for you?

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

3 participants