fproulx / shc-covid19-decoder

Very simple app to decode your Vaccination Proof QR Code (such as the one provided by government of Quebec) - Compatible with SHC (Smart Health Card standard)
https://fproulx.github.io/shc-covid19-decoder/
144 stars 34 forks source link

Where does the hardcoded public key come from? #12

Closed remi closed 3 years ago

remi commented 3 years ago

I was browsing the source code and wondering where does this public key used to verify signature comes from:

https://github.com/fproulx/shc-covid19-decoder/blob/cf2f3b2f2cbd2b0e20bc71ab5745ed79fcc7ad53/src/shc.js#L22-L30

As far as I know, Quebec’s government (my assumption, since you’re from Montreal 🙂) has not released its public key yet 🤔

Thanks!

bonald commented 3 years ago

+1

fproulx commented 3 years ago

I found it somewhere when they leaked it by mistake months ago.

On Wed, Aug 11, 2021 at 11:23 bonald @.***> wrote:

+1

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/fproulx/shc-covid19-decoder/issues/12#issuecomment-896920698, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQSHT2PQSUSIZPLQZMMWTT4KIXLANCNFSM5B6EPCBA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

jcouture commented 3 years ago

It’s not leaking if it’s meant to be public now, is it? :nerd_face:

Any idea why they are purposefully diverging from the SHC Framework with:

<<iss value from JWS>> + /.well-known/jwks.json

which should be (but currently returns a 404 error code):

https://covid19.quebec.ca/PreuveVaccinaleApi/issuer/.well-known/jwks.json

This is clearly described in the SMART Health Cards Framework: https://spec.smarthealth.cards/#determining-keys-associated-with-an-issuer

Don’t get me wrong, it’s very cool you got the public key, but any app adhering to the SHC Framework shouldn’t be able to properly validate the QR code.

(I’m curious about all this, not trying to throw you under a bus or anything)

fproulx commented 3 years ago

Yeah. I think they were told to keep it under wraps for a while so they crippled the public endpoints.

Now that it will be public soon that should be fixed to make it more standard compliant I agree.

Last time I wrote to them by email in may they replied very quickly (the supplier writting it for the gov( On Sat, Aug 14, 2021 at 08:31 Jean-Philippe Couture < @.***> wrote:

It’s not leaking if it’s meant to be public now, is it? 🤓

Any idea why they are purposefully diverging from the SHC Framework with:

<> + /.well-known/jwks.json

which should be (but currently returns a 404 error code):

https://covid19.quebec.ca/PreuveVaccinaleApi/issuer/.well-known/jwks.json

This is clearly described in the SMART Health Cards Framework: https://spec.smarthealth.cards/#determining-keys-associated-with-an-issuer

Don’t get me wrong, it’s very cool you got the public key, but any app adhering to the SHC Framework shouldn’t be able to properly validate the QR code.

(I’m curious about all this, not trying to throw you under a bus or anything)

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/fproulx/shc-covid19-decoder/issues/12#issuecomment-898888552, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQSHUNR4GXCQCQHATNCLDT4ZO3JANCNFSM5B6EPCBA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

sebhtml commented 3 years ago

Now that it will be public soon that should be fixed to make it more standard compliant I agree.

@fproulx @ponahoum @remi @louism @jcouture

You guys are cyber security experts. Do you think that the public key not being public at address https://covid19.quebec.ca/PreuveVaccinaleApi/issuer/.well-known/jwks.json as required by SMART Health Cards Framework makes the recent software acceptance tests at La Cage – Brasserie sportive à Lebourgneuf invalid ?

babelouest commented 3 years ago

My 2c

Although I would love to see the public key publicly available for the public so everyone would verify a QR-code signature the way they want, it's not mandatory to publish the public key as per the smarthealth documentation:

Issuers SHALL publish their public keys as JSON Web Key Sets (see RFC7517), available at << iss value from JWS >> + /.well-known/jwks.json, with Cross-Origin Resource Sharing (CORS) enabled.

I believe they put SHALL instead of MUST in order to comply with users that don't want to publish their public key, whatever the reason the have.

Concerning the tests at La Cage – Brasserie sportive à Lebourgneuf, They may use an application that has the public key hardcoded in it, or they may even not verify the signature... If we can't have access to the application they use, it's hard to know...

Hopefully the public key will be available at some point!

superay123 commented 3 years ago

@fproulx said

I found it somewhere when they leaked it by mistake months ago.

I hope that they did not publish accidently the signing key at https://covid19.quebec.ca/PreuveVaccinaleApi/issuer/.well-known/jwks.json WITHOUT removing the private key parameter 'd'. This would qualify as a major leak and it would be a good reason to remove it. Anybody with this key could sign and render valid fake Quebec QR codes.

It does not seem to be the case as the key is still being used to sign QR codes.

I think that the reason it is not published is due to the kid parameter in the QR code JWS header. Its value kept changing until mid July. When I fetched our QR codes on May 19, mine had a different kid parameter than my wife's QR code. When I got my second shot at the end of June, my new QR code had again a different value for the kid parameter. When my wife got her second shot in mid July, her new QR code had a different kid parameter. However, I fetched again my own QR code and this one had now the same value as my wife's for the kid parameter.

Since then, the value of the kid parameter appears to be stable at 'qFdl0tDZK9JAWP6g9_cAv57c3KWxMKwvxCrRVSzcxvM'. (Can anybody confirm this?)

I guess that the COVID vaccine contest was setup for two reasons. Officially it is to entice people to get their two shots. The hidden reason is to have people fetch their QR code again with the correct stable value for the kid parameter. To have access to the COVID vaccine contest registration form, you have fetch your QR code first!

As @babekouest said, it is not mandatory to publish the signing key and the application they use for the current field tests certainly has the key built in. It probably does care about the value of the kid parameter either.

However, publication of the signing key with the correct kid will be required to enable verification of vaccination status of people travelling abroad via their Quebec QR codes.

steven676 commented 3 years ago

I believe they put SHALL instead of MUST in order to comply with users that don't want to publish their public key, whatever the reason the have.

Internet standards documents with capitalized key words are typically interpreted as in RFC2119, which says:

  1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification.

In other words, my interpretation is that publishing your signing key to iss + /.well-known/jwks.json is a hard requirement of the SMART Health Cards Framework specification.

remi commented 3 years ago

Since then, the value of the kid parameter appears to be stable at 'qFdl0tDZK9JAWP6g9_cAv57c3KWxMKwvxCrRVSzcxvM'. (Can anybody confirm this?)

I have different kid values for both my “first shot” token and my “two shot” token (and it’s not qFdl0t…) 🤔

babelouest commented 3 years ago

You're right, SHALL means MUST, as in

YOU SHALL NOT PASS!

So there's no excuse not to follow the standard.

What I also find very disturbing is the change of the kid value when the public key remains the same. The SMART Health documentation says:

SHALL have "kid" equal to the base64url-encoded SHA-256 JWK Thumbprint of the key (see RFC7638)

Meanwhile, in the QR-Codes I have, the kid used are:

Note: Since the kid in our QR Codes seems to change a lot, it could be assimilated as an identifier, so I won't publish a real used kid value anymore.

But the thumbprint I generate from the public key is:

Not cool...

superay123 commented 3 years ago

As I wrote above, the kid in our QR codes kept changing until mid July. Since July 17th (or maybe earlier) the kid is stable. I downloaded our QR codes again today and the kid did not change.

@remi and @babelouest when did you download your QR codes? If you download it again, what is the kid value?

The PDF layout changed again. The QR code used to be on the left with the vaccine info on the right. Now it is the opposite. Also, within the FHIR bundle, they removed the "gender" field.

remi commented 3 years ago

Oh you’re right. I just downloaded mine again and the kid is indeed qFdl0tDZK9JAWP6g9_cAv57c3KWxMKwvxCrRVSzcxvM 👍

babelouest commented 3 years ago

Mine too, the QR code downloaded a few minutes ago has a new kid...

babelouest commented 3 years ago

The official app is released tomorrow: https://www.lapresse.ca/covid-19/2021-08-24/passeport-vaccinal/l-application-mobile-disponible-mercredi.php

Maybe we'll get some new stuff to analyze out of it :)

remi commented 3 years ago

I just downloaded the source code for the “validator” application (it’s an Expo application): https://d1wp6m56sqw74a.cloudfront.net/@akinox/vaxi-lecteur/1.0.0/1c2676a609f2b32a0a6be8ce507e9e94-41.0.0-ios.js

A quick grep in the code yields :

s.exports={alg:"ES256",kty:"EC",crv:"P-256",use:"sig",kid:"fFyWQ6CvV9Me_FkwWAL_DwxI_VQROw8tyzSp5_zI8_4",x:"XSxuwW_VI_s6lAw6LAlL8N7REGzQd_zXeIVDHP_j_Do",y:"88-aI4WAEl4YmUpew40a9vq_w5OcFvsuaKMxJRLRLL0"}

which confirms that the public key stored in this repo is the one used by the official Quebec Government application!

remi commented 3 years ago

Well, I think we can now close the issue 😅 Thank you all for your input! 👍

superay123 commented 3 years ago

VaxiCode Verif does not care about the kid. I tested with my older QR codes, both with one dose (got red flag) and two doses (got green flag)

pc-coholic commented 2 years ago

Just in case someone is stumbling about this at a later point...

After finally publishing the key with kid qFdl0tDZK9JAWP6g9_cAv57c3KWxMKwvxCrRVSzcxvM on September, 24th, the same key got re-published with kid 2XlWk1UQMqavMtLt-aX35q_q9snFtGgdjH4-Y1gfH1M today, October, 1st.

NickDrouin commented 2 years ago

It seems clear that the QC government is changing/rotating the key ids, 'kid', while using the same 'x' and 'y' for the Elliptic Curve public key. This is odd, but not entirely out of spec.

What is out of spec, is that their JWKS endpoint is not returning a fully-populated array of keys: it only returns the latest. This breaks any normal signature validation flow for the JWT, as the KID in the header is not found in the JWKS response. @fproulx , if you know how to file a bug with Akinox, please do so, or let me know.

You may find the following useful, if you are looking into reading these QR codes in a spec-compliant way: https://demo-portals.smarthealth.cards/VerifierPortal.html It does the full flow, and we can see that the lack of the 'nbf' is non-compliant for the SMART spec, in addition to the JWKS missing the full set of keys for all issued QR codes.

NickDrouin commented 2 years ago

Note: the new "Pan-Canadian" version of the QR codes, released today and available for download, are FHIR 4.0.1 bundles and seem compliant using the test portal link, and work well with https://fproulx.github.io/shc-covid19-decoder/