Thalhammer / jwt-cpp

A header only library for creating and validating json web tokens in c++
https://thalhammer.github.io/jwt-cpp/
MIT License
855 stars 233 forks source link

Using certificate chain in x5c in header #296

Closed JBarberU closed 9 months ago

JBarberU commented 1 year ago

What's your question?

Using certificate chain in x5c in header

Additional Context

I'm looking at verifying a jwt that has the certificate chain for its signing key embedded in x5c in the header (base64 encoded DER format).

Looking at examples it seems to me that I'd need to parse the json, grab the correct certificate from x5c and then use the key to verify the signature using the appropriate algorithm. I'm assuming the certificate chain isn't verified for me and I'd need to do that too?

Just wanted to verify if this is correct or if there is a simpler way.

Thanks!

prince-chrismc commented 1 year ago

Is the example missing something https://github.com/Thalhammer/jwt-cpp/blob/ad08c684a2bf9db413786e800e0d92e65772d9d6/example/jwks-verify.cpp that you are specifically looking for? You seem to have grasped the workflow really well.

certificate chain isn't verified for me and I'd need to do that too?

To my knowledge when the certificate is loaded into OpenSSL it should verify the certificate, depending on your system this would be DNS and comparing against the root keys, expiration etc.

I do recall this being a challenge when the key chain came programmatically... https://stackoverflow.com/questions/16291809/programmatically-verify-certificate-chain-using-openssl-api so you need to setup an X509 store are I recall

JBarberU commented 1 year ago

Hey, thanks for the quick reply!

I should have clarified, what I'm trying to do is embed the certificate chain directly in the jwt rather than using jwks (to have a completely self contained jwt).

I'm not sure how common the use for this is, but the use-case I have is this:

I think using jwks would be the optimal solution (not needing to send the whole certificate chain with every single api call), but I'm working on a constrained system where adding endpoints on machine A is a bit dubious (https://some-domain.tld/.well-known/jwks.json).

I was able to verify the signature by grabbing the first certificate from the x5c using something like this:

auto header = decoded.get_header_json();
const auto x5c = header["x5c"].get<picojson::array>()[0].get<std::string>();
const auto x5c_pem = jwt::helper::load_public_ec_key_from_string(x5c_pem);

auto verifier = jwt::verify()
    .allow_algorithm(jwt::algorithm::es384{x5c_pem});

verifier.verify();

But the issue I have now is that, as far as I know, there's no verification of the certificate chain and I'm not sure how to do that best. I suppose I could dive into and use openssl to do that verification, but it seems like something that would fit nicely into the scope of jwt-cpp. I wouldn't mind implementing it and submitting a PR if it's something that might be of interest.

prince-chrismc commented 1 year ago

what I'm trying to do is embed the certificate chain directly in the jwt rather than using jwks (to have a completely self contained jwt).

That's a security risk IMO and you probably do not want to do that.

Anyone can make a cert chain and sign a token and you would always verify and accept it which could include malicious actors.

On the surface, I am a little skeptical is would be a feature but we are open to any contributions

prince-chrismc commented 1 year ago

I'm not sure how common the use for this is, but the use-case I have is this

I think this is exactly the normal use case, your machine A and application are the "authorization server" and the device, machine B, is the "client".

ideally the root certificate is installed in both machines and the server published it public key (and intermediates because they roll over). This way it can be verified by any clent.

generally the cert changes on the time scale of months or years, so you'll want to cache so it's one API call ones when you startup -- it's a common shortcut -- there's way to inspect the cert and get the expiration date and refresh on half-life. The industry I worked it that was the best practice.

The public root should not be in the chain, it's a device specific setting the users (or automatic service) should install

prince-chrismc commented 9 months ago

I am going to mark this as complete, hopefully it was helpful discussion