ehn-dcc-development / eu-dcc-hcert-spec

Electronic Health Certificates Specification
363 stars 40 forks source link

Clarify KID and maybe refer to public key instead of cert #61

Closed wkornewald closed 3 years ago

wkornewald commented 3 years ago

The spec doesn't clearly state what the kid refers to. In the Kotlin implementation it seems to refer to the shortened SHA-256 digest of the DSC.

Also, instead of referring to a DSC digest, you can increase the flexibility by referring to a public key digest (i.e. the key within the DSC). This allows for extending the validity of an existing DSC without invalidating existing HCERTs. This can reduce the impact of mistakes and increase security with shorter lived DSCs. You'd simply reuse the existing key pair to create a new DSC. If you want to explicitly invalidate existing HCERTs you can still generate a new key pair.

jschlyter commented 3 years ago

The `kid´ in the HCERT refers to the kid on the trusted list - see https://github.com/ehn-digital-green-development/hcert-spec/blob/main/hcert_spec.md#a1-the-key-identifier-kids. The note is important as verifiers do not need to know about how the kid came about, they only need to match between the kid in the HCERT with the ones on the trusted list.

wkornewald commented 3 years ago

And how do you get each kid from the trusted list? Currently, the kid seems to be the shortened cert digest and this means the verifier needs to know how to derive the kid for the trusted list and you don’t get the flexibility of a public key based kid. Or did I misunderstand something?

Or will the kid be the (shortened?) Subject Key Identifier in the final spec?

BTW, does JWKS have any advantage over a standard PEM file? PEM seems simpler and has ready made parsers in many languages.

jschlyter commented 3 years ago

To be useful, a trusted list must contain information about the issuer (name, country etc), public key parameters as well as the key identifiers. If this is communicated using certificates (PEM), in which case the receiver of the trusted list must calculate the kid as described in Appendix A.1.

I would personally recommend that the trusted list is constructed as a (signed if required) JWKS. An example is provided in the testdata repository. The upside of that is that kid, public key parameters and additional data about the keys (e.g., issuer) is easily consumed by modern applications. YMMV and PEM might fit your bill better.

dirkx commented 3 years ago

@wkornewald just to avoid confusion - we are trying to keep the QR as small as possible (100's of bytes) - so there is only room for a couple of bytes really for this certificate reference. And hence the shortened KID.

wkornewald commented 3 years ago

The reasoning behind shortening is clear.

I just wasn’t expecting that we’d want to avoid X.509 and go with JWKS. That’s the reason for my confusion because it thought we’d just read the SKID extension from the X.509 and use that (shortened) as the kid. But with JWKS there is no X.509 of course unless everyone additionally creates them, but why use both if just one is sufficient?

Also, every language should have APIs for working with X.509 and parsing PEM and you can construct cert chains and validate them with existing tools in case you want to have root and intermediate certs. The advantage of JWKS isn’t quite clear to me because it’s not a real replacement for X.509. Our team is currently using cert chains and we’d have to discuss the implications of going with JWKS.

dirkx commented 3 years ago

So you can still use the whole PEM/X509 and validate the chain. It is just that the (leaf or intermediate) certs are not in the QR. Nor is the public key.

In theory - you could even ignore the KID and simply validate against all your known trusted public keys.

thinkberg commented 3 years ago

you could even ignore the KID and simply validate against all your known trusted public keys.

That is not practical. We may get a potential larger number of certificates that would need to be tested each time.

wkornewald commented 3 years ago

You mean even with JWKS all countries will additionally issue X.509 certs and the JWKS is just derived from that? With the JWKS suggestion in the spec I’m afraid that countries will only issue a JWKS with public keys and then we can’t have X.509 anymore (we definitely don’t want to implement JWKS as a fallback).

jschlyter commented 3 years ago

It is up to each member state to construct their list of of trusted keys. At the end of the day, the trusted list still needs to contain a list of keys with name and kid. The format of the trusted list of out of scope of the HCERT specification.

Per A.3.1 the secretariat will maintain a public, integrity (secure) protected, single, up to date, aggregated, list of all CSCAs (DGCG). You can always this list as source for your own trusted list.

dirkx commented 3 years ago

@wkornewald no pure JWKS with public keys is NOT a forseen option - the Europan DGCG will only handle and allow the upload and management of a CSCA in X.509 form that signs a DSC in X.509 format - and distribute these as X.509s - closely aligned to the current ICAO model for eMRTD and the WHO model for this.

See the https://ec.europa.eu/health/sites/health/files/ehealth/docs/trust-framework_interoperability_certificates_en.pdf, the trust managment section in https://ec.europa.eu/health/sites/health/files/ehealth/docs/digital-green-certificates_v1_en.pdf https://ec.europa.eu/health/sites/health/files/ehealth/docs/digital-green-certificates_v2_en.pdf and https://www.who.int/publications/m/item/interim-guidance-for-developing-a-smart-vaccination-certificate

wkornewald commented 3 years ago

Alright, this clarifies it. And would the kid be the X.509‘s shortened SKID? This way a PEM could contain all information without needing a JWKS and you still wouldn’t have to know how the SKID came about. Just the shortening would be the only detail for verifiers to take into account.

dirkx commented 3 years ago

No - it is the first 8 bytes of the SHA256 fingerprint. The reason for not using SKIDs is that some countries may use existing eMRTD certificates, such as BCS certs that do not have SKIDs due to size limits.

wkornewald commented 3 years ago

Could we then please require using the first 8 bytes of the SKID if one exists and fall back to the first 8 bytes of the SHA-256 fingerprint? Then we can still have the advantages of using the SKID where possible. I hope this doesn't add too much complexity to the spec.

jschlyter commented 3 years ago

Could we then please require using the first 8 bytes of the SKID if one exists and fall back to the first 8 bytes of the SHA-256 fingerprint? Then we can still have the advantages of using the SKID where possible. I hope this doesn't add too much complexity to the spec.

If you have the certificate, why not simply calculate the hash? It is a one time operation when one import the list of certificate into the verifier.

wkornewald commented 3 years ago

Because the hash refers to the whole X.509 certificate instead of just the public key. This is the whole reason why cert pinning was considered a failure. The new best practice is to pin the public key, not the certificate. This allows for e.g. extending the validity of an existing X.509 by simply creating a new X.509 and reusing the previous public key. This way all existing HCERTs stay valid because the kid doesn't change. However, if the kid refers to the hash of the X.509 you can't do that because the hash changes, so all existing HCERTs become invalid.

wkornewald commented 3 years ago

Oh we can simplify this some more: The spec could require the kid to be the first 8 bytes of the hash of the X.509's public key (instead of hashing the whole X.509). This way we have a single, simple rule like before, but at the same time more flexibility (and mistakes are less fatal). In most certs the SKID would just happen to have the same value as the public key hash, but that wouldn't be relevant to us.

jschlyter commented 3 years ago

@wkornewald all good ideas, but I think the ship has sailed. Could it be better? Yes, but people are already implementing and we need to move on.

wkornewald commented 3 years ago

Since you are considering a change of the encoding, could you please also consider this really trivially tiny change, too?

asitplus-pteufl commented 3 years ago

@wkornewald while agree on your analysis on pinning and cert renewal, one opinion and one question: (except for the fact, that like @jschlyter has said, this cannot be changed anymore)

wkornewald commented 3 years ago

This

Think of it this way: Replacing a certificate currently leads to invalidating tens of millions of HCerts. We should do everything to avoid unnecessary HCert invalidation because so many people are affected and it would be a non-trivial effort to correct the situation (by issuing tens of millions of new HCerts). Such an effort would dwarf the tiny implemenation effort we could do now as a preparation. You might not see the need right now, but with so many countries and people involved, mistakes are more likely.

Regarding your question: If we use the (shortened?) SKID it wouldn't really matter which key format is used. The issuer of the cert decides how the SKID is computed and our HCert's kid would only identify based on SKID. When issuing a new cert the SKID just needs to be computed in the same way.

asitplus-pteufl commented 3 years ago

there are multiple perspectives/topics right now, but regarding the answer to my question, let me check if we have the same perspective here:

do you have the same view on this?

wkornewald commented 3 years ago

Yes, I think this looks right.

jschlyter commented 3 years ago

IIRC we had a discussion about this earlier and the choice to hash the certificate very deliberate. Perhaps @dirkx, @martin-lindstrom or @Razumain can recap?

dirkx commented 3 years ago

As to the original reasoning:

So first - in the eMRTD/mDOC world it is common for (barcode) signing certificates to be very small - and hence not have a SKI or any such data.

E.g. see table 4 in https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf and the appendix (x means 'do not use — the field MUST NOT be present').

So effectively the lowest common denominator are things like the fingerprint of the certificate or some hash over the public key (or the public key itself).

The fingerprint (i.e. the SHA256 of the DER encoded x.509) is very standard - and very interoperable between tooling (And this also sidesteps the window/tooling 2-byte ASN.1 prefix that also plagues cut-and-paste of the fingerprint/SKI & the debate if the SKI its its value or the oncted string)).

So hence the choise for this thing which is the easiest to get interoperable.

Size matters - so hence the 8 bytes cutoff.

wkornewald commented 3 years ago

So, it's a matter of simplicity of creating a cert hash vs. all the benefits of using the public key hash? I think the priority should be on the benefits of public key pinning.

vitorpamplona commented 3 years ago

The priority should be making sure the kid, whatever it is, is resolvable at the verification time. The solution could be very short, and very informative.

Let's take Austria as an example. Today, WTOXYrYS47o is one of their KIDs. A structure like this forces verifiers to not only have a cached trust list somewhere but also to build their own servers to update such trust lists and push to their apps from time to time. Each verifying vendor can then use their own key servers to trace users around.

A second option would be to force the ISSUING COUNTRY inside the payload to be the same as the country of the KEY. As you know, the issuing country can be different than the country of test/immunization. In this case, verifiers first unpack the payload to look for the co field, and then hard code that AT to Austria's Master List. This still requires an intermediary server that is managing trust list updates for all countries for each verifying vendor, but at least there are no assumptions on which country the signature is coming from.

A third option would be to add the Issuer to the kid as: AT:WTOXYrYS47o. In this option, verifiers would hardcode the AT from the kid itself to the Master List from Austria. They can also hardcode a simpler AT -> dgc.a-sit.at/ehn/ and resolve the kid from there. In this case, verifying vendors don't need to build a key management server (less tracing of users) and master lists are not even needed.

A fourth option is to add the full URL directly in the kid as: dgc.a-sit.at/ehn/WTOXYrYS47o. In this case, verifying vendors don't need to worry about master lists at all or building their own key-updating servers, and will simply call the address if the app doesn't have a cached version of that public key.

We can also have a forwarder service available in a shorter domain: dgc.go/AT/WTOXYrYS47o -> dgc.a-sit.at/ehn/WTOXYrYS47o

I would easily pay 10 bytes to avoid all the added complications, lack of privacy and potential bugs of the first 3 options.

Of course, the best options are DID:DGC:AT:WTOXYrYS47o which uses a universal DID resolver or a WTOXYrYS47o.dgc.a-sit.at, which uses a DNS Lookup. But there might be way too much convincing to get these 2 options to be considered.

asitplus-pteufl commented 3 years ago

@vitorpamplona not clear where you are aiming at ... leaving policy aside and sticking to technical/privacy/sec arguments:

since the central EU GW is not publicly available (also due to policy reasons) the member states will compile such trust-lists containing all DSCs in some or another way

jschlyter commented 3 years ago

@vitorpamplona please also remember that any online lookup of keys, without additional security requirement like DNSSEC, effectively moves trust from the official trusted list to DNS (via WebPKI). Although applications like TLSA or CERT RR (application keys in DNS with DNSSEC) could be used to remove the WebPKI intermediate step, it would still be a non-official key distribution mechanism.

vitorpamplona commented 3 years ago

The discussion here is just to make the kid automatically resolvable if verifiers want to resolve. It doesn't affect policies, or any other security concern. It's on how to create the ID for the key, not on if I can trust the link in that ID.

Every verifier has risk management policies of its own. It's up to them to decide what to do with the ID.

My point is that a well specified, more resolvable, unique ID is better than an ambiguous ID that is implemented today.

you do not want online calls (this can lead to privacy problems in certain cases) and goes against the offline requirements

Online calls will happen, either to my key server or directly to the country's website, in bulk or individually. But they will happen. There will be millions of keys out there. Apps won't store everything on devices. There's no other way.

I have my own mechanisms to make sure these calls are private. None of which needs to be in the spec.

problem of trust

As a verifier, I have my own trust policies. I am not saying to kill the master lists or certificate chain. I am proposing to change the ID on how to find them. Trust policy is dependent on the use case. Verifying signatures of the types of extremely low-risk certificates within the DGC context, for instance, can use many existing solutions out there. Outside the DGC context, there are way more threatening payloads that I have to worry about extreme security. The DGC is not one of them.

no individual certificate will be downloaded

My apps will, no matter what you do. My question to you is, do you wish my apps to download them from a private provider like myself (or a partnering company), or do you wish me to download directly from the original source?

without additional security requirement like DNSSEC, effectively moves trust from the official trusted list to DNS (via WebPKI)

Correct. But the manual download of the master list as of today MUST ALSO trust the DNS. There's nothing you can do to avoid the trust on the DNS resolver. If the Master list is transferred online, in any way, you are trusting the underlying architecture in the same way you would have to trust the DNS to download an individual key directly to the verifying app.

jschlyter commented 3 years ago

Correct. But the manual download of the master list as of today MUST ALSO trust the DNS. There's nothing you can do to avoid the trust on the DNS resolver. If the Master list is transferred online, in any way, you are trusting the underlying architecture in the same way you would have to trust the DNS to download an individual key directly to the verifying app.

This is why I claim that the trusted list should be signed out of band, e.g with JWS, or by validating each DSC against its CSCA (that is fetched out of band).

vitorpamplona commented 3 years ago

This is why I claim that the trusted list should be signed out of band, e.g with JWS, or by validating each DSC against its CSCA (that is fetched out of band).

You are still trusting the DNS to get the original CSCA.

jschlyter commented 3 years ago

You are still trusting the DNS to get the original CSCA.

No, they can be exchanged out of band are are long-term stable. The key (pun intended) is to validate the list of DSC with something that is not fetch from the DNS.

vitorpamplona commented 3 years ago

You are still trusting the DNS to get the original CSCA.

No, they can be exchanged out of band are are long-term stable. The key (pun intended) is to validate the list of DSC with something that is not fetch from the DNS.

If it follows what happened with the Passport Master List (black market on day 2), they will never be exchanged out of band. There are a lot of lessons from that model.

vitorpamplona commented 3 years ago

But the discussion here is not on what to use to download the certificates. It's on how to define the key to find those certificates. My proposal is to make it so that, if verifiers want, they could download it directly.

We can call the individual download of keys a semi-secure verification that happens only temporarily between updates on the master lists. The app checks with the official master list first and if it's not there, it tries to find the key while reporting to the user that the verification was not double-checked by the master list. In this way, the app doesn't block service just because the cached list is outdated.

If verifiers don't want to download it directly via the web (their decision), they already have the option of going out of band, or explore other ways. That hasn't changed.

You can do dgc.go/AT/WTOXYrYS47o and still download the entire key list offline if you think security is a concern.