Make approved trust list publicly accessible

Why would you put the master trust list behind mTLS auth?
Priority should be assigned to distributing a verifiable trustlist to everyone who wishes
to validate the contents of DGCs. The certificates/pkeys are not sensitive
and should be made accessible to everyone.
If you don't want to serve this via an API at least
consider hosting a static daily dump (+ signature) of the trustlist in a publicly
accessible location.

+1 on this.
We are also searching for a public trust list.
We found a list hosted by the TU-Graz (AT)
https://dgc.a-sit.at/ehn/cert/listv2
https://dgc.a-sit.at/ehn/cert/sigv2
https://dgc.a-sit.at/ehn/
regards
Julian

using this list we are able to validate barcodes issued in Austria
the list also contains several other countries

As far as I know, no official list exists, as the details on how to proceed with private contractors and non-EU countries are still under discussion.
This a decision that needs to be made on EU level, not something we as a contractor can do, but I'll bring it up with the colleagues involved in the topic to see if there is a status update.

Most countries publish their public certificates - as they are public.
However the company & their expert suppliers that operates the joint gateway are concerned of all sort of 'attacks' - and for this reason insists on putting the joint list of public keys behind TLS-client auth.
The reasoning behind this is not entirely clear to most of us.
The Netherlands publishes its public keys at https://www.npkd.nl/csca-health.html - publicly.

Thanks, ok I get the point, and its also not entirely clear for us ;)
Thanks for the list of NL keys.
Do the Netherlands also publish the full joint list?
Austria is currently only publishing a test list here:
https://dgc.a-sit.at/ehn/
But is just a test.
Will try to get into contact with officials and keep you updated.
thanks

There seems to be a multitude of open issues around github regarding the access to a global trustlist and they all point here, let me share my experience and thoughts.
I was able to get access to the list via our (Finland) national provider in half a day (1 email & 1 webform today) and I've implemented a certificate database which downloads new certs and the list of valid key ids (for pruning old ones) regularly.  I can validate the COSE of my own vaccination EHC successfully with the FI-issued public cert.
My database currently has 133 active certs from AT BE BG CY CZ DE DK EE ES FI FR GR HR HU IE IS IT LI LT LU LV MT NL NO PL PT RO SE SI & SK. Of course I cannot share the database or open a JWKS type service because that would put me in a man-in-the-middle position (no amount of disclaimers would stop people from trusting the informal list of keys).
I fully understand that the EU wishes to allow member states to implement their own backends for this and also filter certs or add national variants etc.. but still this seems overly complicated that not even the list of valid cert fingerprints (from which the first 8 bytes are used as key ids) is not published as a static & signed list anywhere. I strongly feel that some sort of discovery service run by the EU would be a bare minimum (returns a JSON object of country codes mapped to metadata including API URLs) and that member states should run a JWKS-style public service for keys.
I have no idea how well prepared other countries are to support developers and I applaud our officials for the straightforward process and quick turnaround (they are also updating the public websites based on my feedback).
Maybe this github repository could include links to every national provider of the trust store so developers know who to contact?

I totally agree. JWKS style public keys is what the SMART Health standard used by some canadian provinces and California is using for their vaccination QR codes: https://github.com/smart-on-fhir/health-cards/blob/main/docs/index.md

Here is my contribution: https://github.com/lovasoa/sanipasse/blob/master/src/assets/Digital_Green_Certificate_Signing_Keys.json
This is a versioned and automatically updated list of signing keys from all member states, extracted automatically from the french backend, and updated twice per day.

I agree with the discussion here. If the list is not publicly available, at least there should be a simple verification process to get an API key to get access to the list, with all the protection/throttling/terms and conditions associated with it. This is unnecessarily imposing restrictions for building on this further, especially for services across-state.

Here is my contribution: https://github.com/lovasoa/sanipasse/blob/master/src/assets/Digital_Green_Certificate_Signing_Keys.json
This is a versioned and automatically updated list of signing keys from all member states, extracted automatically from the french backend, and updated twice per day.

This is great - I am going to get in touch with the Swedish counterpart and see if I can get a list. If more people could do the same, one could simply download all of them to verify and not have to rely on just one.

I agree with the discussion here. If the list is not publicly available, at least there should be a simple verification process to get an API key to get access to the list, with all the protection/throttling/terms and conditions associated with it. This is unnecessarily imposing restrictions for building on this further, especially for services across-state.

@jbx1 As it is, this is not a technical but a political issue. Member states have sovereignty over the trust list, not the European Commission, that is why there is no central list, nor a central place to request access. However member states are free to provide easy access to the list if they so choose.

Actually - I’ve not heard that argument made. If that is indeed the reason - fair enough. But sofar - the arguments made by the operators is that they worry (rightly/fairly) about a deluge of trust-list fetches from verifiers in the field - with whom they have no relation / no desire to serve.

@daniel-eder Yes I understand the reasoning might have been political, but it makes no sense at all. How state A has sovereignty to share the public key of an unrelated state B within the territory of state B is beyond me. When state B is sharing its public key (which by its very nature is public, so safe to share) with all other member states, it is doing effectively the same thing. There could still be verifications that who is requesting them is an EU company/resident, just like is done in .eu domains, and make it available through an API key, to at least even protect against DDOS attacks etc.

I just found the trust list provided by Germany:
https://de.dscg.ubirch.com/trustList/DSC/
Its in yet another format. Documentation:
https://github.com/Digitaler-Impfnachweis/certification-apis/tree/master/dsc-update
They say it's rate limited, but not how exactly.
I didn't manage to verify the signature of the trust list itself, though. See my question here:
https://github.com/Digitaler-Impfnachweis/certification-apis/issues/157

Here is my contribution: https://github.com/lovasoa/sanipasse/blob/master/src/assets/Digital_Green_Certificate_Signing_Keys.json
This is a versioned and automatically updated list of signing keys from all member states, extracted automatically from the french backend, and updated twice per day.

Nice!
We have created a mirror for public known trustlists.
We access to the German / Austrian and thanks to this post to the French trust list.
The Austrian Trustlist is encrypted but the required keys are also accessable.
We well add the Austrian Trustlist in the next days.
https://github.com/section42/hcert-trustlist-mirror/settings
Maybe this will help someone.
regards

Where is the official Austrian trust list? I'm from Austria and would need that one but can't find it, only the test list mentioned above.

We found the trustlists by looking at the check apps provided by the different countries.
Austria is for example using this web page: https://greencheck.gv.at/
And the app is making a request to this endpoint: https://greencheck.gv.at/api/masterdata
were you can find the trustlist.

Thank you so much! So it's not an official endpoint, but better than nothing! Have to find out how it's encrypted tomorrow.

i think a *.gv.at domain is official enough ;)
but you are right the all of the lists we found so far, were discovered by reverse engineering
i think its base64 and cbor, but can tell you more tomorrow

Sweden: https://dgcg.covidbevis.se/tp/trust-list

CBOR and Base64, got it! Already implemented it. See: https://github.com/panzi/verify-ehc :D

Sweden: https://dgcg.covidbevis.se/tp/trust-list

thanks, looks like some sort of base64 and jose ?
will have a look at it 👍

CBOR and Base64, got it! Already implemented it. See: https://github.com/panzi/verify-ehc :D
i have pushed an github action to fetch and decode https://github.com/section42/hcert-trustlist-mirror
feel free to use it

I just found the trust list provided by Germany:
https://de.dscg.ubirch.com/trustList/DSC/

There's also a test/dev endpoint at:
https://de.test.dscg.ubirch.com/trustList/DSC/
You should use this for development purposes to avoid throttling at the production endpoint.
The first line of the answer is a signature added by the national trust list issuer. This is to verify that the trust list has been issued by the German authority. The trust list in the format specified by EU-DGC begins at line 2.
For details see
https://github.com/Digitaler-Impfnachweis/certification-apis/blob/master/dsc-update/dgc-update-api.yaml
and
https://eu-digital-green-certificates.github.io/dgc-gateway/#/Trust Lists/downloadTrustList

We have a full implementation of DGC, including signature verification, implemented in typescript in sanipasse : https://github.com/lovasoa/sanipasse/blob/master/src/lib/digital_green_certificate.ts
Would you be interested in extracting that to a library and publishing it to npm ?

Austrian list implementation and verification in these cores:
IOS: https://github.com/ehn-dcc-development/ValidationCore
Kotlin/Java/JS: https://github.com/ehn-dcc-development/hcert-kotlin

This is all very great guys, thanks to everyone posting his information.
Does any one know if the UK certificate or public keys were integrated/are going to be integrated any time soon? I know there were some discussions between the EU and the UK to make the NHS one interoperable with the DGC.

This seems to contain the UK public keys (no certs, just the keys)
https://github.com/andypandy47/Answer-Digital-Verifier-App/blob/4d79843334c556729ab1c611d02c6244ba8d6f37/VerifierApp.Electron/src/assets/publicKeys.json

We have a full implementation of DGC, including signature verification, implemented in typescript in sanipasse : https://github.com/lovasoa/sanipasse/blob/master/src/lib/digital_green_certificate.ts
Would you be interested in extracting that to a library and publishing it to npm ?

What license would that have and would it work in the browser or only nodejs?

As a member of the public and EU vaccine certificate holder, I am here to say that it is absolutely crazy that we hold vaccine certificates that cannot be easily authenticated by anyone who asks worldwide. I appreciate that Luxembourg has issued a publicly accessible verifier app, but how is your average immigration official in a deep Africa or Asia or South America supposed to know that he has to use the Luxembourg app to authenticate certificates shown to him?
Our certifcates are basically useless outside the EU if nobody can easily verify their authenticity.

In the Netherlands we have two scanners. One for domestic use and one for border use.
The domestic scanner accepts all domestic QR codes and all EU (but non-NL) DCC QR codes.
The border scanner accepts all EU DCC QR codes.
Both scanners are available in the Apple and Google stores.
The trust list of all EU certificates is provided via an API which is loaded by both scanner apps. It is publically available.
If you wish to build your own scanner, you can checkout & build our code. https://github.com/minvws/nl-covid19-coronacheck-app-coordination/

Anyone know how to verify the signature of the Austrian trust list? I've found a few pem certificates in their obfuscated JavaScript, but couldn't verify the trust list signature with any of them. Not like this:
pubkey.verify(sign, trust_list, ECDSA(hashes.SHA256()))

And not like this (this is what works for the German trust list):
r = int.from_bytes(sign[:len(sign)//2], byteorder="big", signed=False)
s = int.from_bytes(sign[len(sign)//2:], byteorder="big", signed=False)
sign_dds = encode_dss_signature(r, s)
pubkey.verify(sign_dds, trust_list, ECDSA(hashes.SHA256()))

What license would that have

Sanipasse is under the GPLv3 : https://github.com/lovasoa/sanipasse/blob/master/LICENSE

and would it work in the browser or only nodejs?

It works in node and the browser, and is in production as an isomorphic app. The same certificate checking code runs on the frontend and the backend.

Yeah, GPL doesn't work for my use case, so I wrote something myself. Need to ask my boss if I can publish that under the MIT license.

I wrote a version that works entirely out of the browser. I do utilize a service to deliver the certificates, but there's no reason this couldn't be done from a static file.
https://edgcheck.web.app/
Can't release source at this moment as I would also have to inquire at work first.

I wouldn't recommend to anyone putting their private health data on a closed source app by a private company hosted on firebase !
You can already use https://sanipasse.fr , which preserves privacy, is open source, and hosted in Germany.

It may be safer in this international context to use something like the Apache 2 license as it has the required contributor and patent clauses too.

I wouldn't recommend to anyone putting their private health data on a closed source app by a private company hosted on firebase !
You can already use https://sanipasse.fr , which preserves privacy, is open source, and hosted in Germany.

No worries at all. Removed the link. This is not a competition.

I'm not sure what you mean. sanipasse does work entirely in the browser.

You mentioned it requires a nodejs service to run. If all processing happens in the browser then the certificates could also be loaded statically. That way this could be hosted anywhere, not requiring any specific hosting solution.

@lovasoa any idea why the keys in the French list has some of the keys in a different format?  Some of them start with "MFkwEwY" while a few start with "MII" (which seems to be the common format used also in the ACC environment).
When one checks the list of the German list, all of them start with "MII" too.
Checking individual KIDs, the KIDs match (I only checked a few like the German and Norway ones) but the public key is different.
For example KID 0L7AaIwu+EY=  starts with MIIHUTCC in the German list, but in the French list it starts with MFkwEwYHK.

Interesting finding. Did you investigate whether it was the same public keys (same prime product) encoded differently, or entirely different public keys ? The json list in sanipasse is exported by decoding the x509 certificates, extracting the public key, and reencoding it with webcrypto.

That's what I thought at first, but then some of them seem to be in the same format, starting with MII. I didn't investigate deeply to see if it was actually the same public key somehow encoded differently.

Just op the base64 string in here. MII is indeed the ASN1 encoding of the heading of most X509's - and quite a few chuncks are identical.
If you want to read them - do
base64 -D | openssl x509 -text -noout -inform DER

to see what is in them. Or
base64 -D | openssl asn1parse -inform DER

if it is obscure. The 'base64 -D' is purely to go from Base64 to pure binary.

Specific example. The AT key in the DE trustlist:
    {
      "certificateType": "DSC",
      "country": "AT",
      "kid": "Is2JtrOJhik=",
      "rawData": "MIIB7zCCAZagAwIBAgIKAXnM+L47fmBcezAKBggqhkjOPQQDAjBEMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQwwCgYDVQQFEwMwMDExFjAUBgNVBAMMDUFUIERHQyBDU0NBIDEwHhcNMjEwNjAyMTM0NTI0WhcNMjMwNjAyMTM0NTI0WjBGMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQ8wDQYDVQQFEwYwMDEwMDExFTATBgNVBAMMDEFUIERHQyBEU0MgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGBNuKiCpnXH0VlIdk6pJZH2ep8jQaV+FR3izMXxZfK5EPGZLtG3Jx+TmV3JJErfrSrPhRmfbSidVbTQ5nnZS+ujbjBsMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUNs2smrjBhuR5Bqxl6teE1x1o2ycwHwYDVR0jBBgwFoAUHyKsHGUWKbTBmLNjb7/dCZ27e3swGgYDVR0QBBMwEYEPMjAyMTEyMTYxNDQ1MjRaMAoGCCqGSM49BAMCA0cAMEQCIDjXHnyzq3sTisMX1uY8xQ2ZqCRL2xmxtYOPhSZ9ZacYAiAqHUMOC7WNgq4h28n31WLc1mMPAYauWslSEwnXC79AGw==",
      "signature": "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCAMIIB0zCCAXmgAwIBAgIKAXnM+Z2p0IjczzAKBggqhkjOPQQDAjBEMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQwwCgYDVQQFEwMwMDExFjAUBgNVBAMMDUFUIERHQyBDU0NBIDEwHhcNMjEwNjAyMTM0NjIxWhcNMjIwNzAyMTM0NjIxWjBFMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQ8wDQYDVQQFEwYwMDEwMDExFDASBgNVBAMMC0FUIERHQyBVUCAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElD1yV24BEVOMfPyu8zrPmDSUPvfinTSdos8PqTQWIbiJlKsULudv/tPt5iv+Op+04GHORjhVTNQ6OEk0iF8B96NSMFAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBQfnVl93OqxshorGeh28AEVN0BD2jAfBgNVHSMEGDAWgBQfIqwcZRYptMGYs2Nvv90Jnbt7ezAKBggqhkjOPQQDAgNIADBFAiAlsEe7pgYuY9VXjiHpziFQJoaEvEkUjoquEHWQ8jXpfAIhAM4ygjPC+FijbF+gtDzV0MtxdyiFmvvVaicALHXbUdaoAAAxggFWMIIBUgIBATBSMEQxCzAJBgNVBAYTAkFUMQ8wDQYDVQQKDAZCTVNHUEsxDDAKBgNVBAUTAzAwMTEWMBQGA1UEAwwNQVQgREdDIENTQ0EgMQIKAXnM+Z2p0IjczzANBglghkgBZQMEAgEFAKCBlTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMTA3MDIwOTMyMzVaMCoGCSqGSIb3DQEJNDEdMBswDQYJYIZIAWUDBAIBBQChCgYIKoZIzj0EAwIwLwYJKoZIhvcNAQkEMSIEICLNibaziYYp6Z0LGju9wly98mRMdY28rQJ+eTyediX1MAoGCCqGSM49BAMCBEYwRAIgc/M10UbXsN5jBeBLYNaGYt4JpjcJYqGRB7Hg/73K2J0CIAIGylViXcevYgbRZepG1Z1mb5KWFDEG/HkukVOXhjstAAAAAAAA",
      "thumbprint": "22cd89b6b3898629e99d0b1a3bbdc25cbdf2644c758dbcad027e793c9e7625f5",
      "timestamp": "2021-07-02T11:32:35+02:00"
    },

I can parse the rawData like so:
% echo -n 'MIIB7zCCAZagAwIBAgIKAXnM+L47fmBcezAKBggqhkjOPQQDAjBEMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQwwCgYDVQQFEwMwMDExFjAUBgNVBAMMDUFUIERHQyBDU0NBIDEwHhcNMjEwNjAyMTM0NTI0WhcNMjMwNjAyMTM0NTI0WjBGMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQ8wDQYDVQQFEwYwMDEwMDExFTATBgNVBAMMDEFUIERHQyBEU0MgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGBNuKiCpnXH0VlIdk6pJZH2ep8jQaV+FR3izMXxZfK5EPGZLtG3Jx+TmV3JJErfrSrPhRmfbSidVbTQ5nnZS+ujbjBsMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUNs2smrjBhuR5Bqxl6teE1x1o2ycwHwYDVR0jBBgwFoAUHyKsHGUWKbTBmLNjb7/dCZ27e3swGgYDVR0QBBMwEYEPMjAyMTEyMTYxNDQ1MjRaMAoGCCqGSM49BAMCA0cAMEQCIDjXHnyzq3sTisMX1uY8xQ2ZqCRL2xmxtYOPhSZ9ZacYAiAqHUMOC7WNgq4h28n31WLc1mMPAYauWslSEwnXC79AGw==' | base64 -d | openssl x509 -text -inform der
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:79:cc:f8:be:3b:7e:60:5c:7b
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = AT, O = BMSGPK, serialNumber = 001, CN = AT DGC CSCA 1
        Validity
            Not Before: Jun  2 13:45:24 2021 GMT
            Not After : Jun  2 13:45:24 2023 GMT
        Subject: C = AT, O = BMSGPK, serialNumber = 001001, CN = AT DGC DSC 1
[…]

The same AT key in the FR trustlist:
  "Is2JtrOJhik=": {
    "serialNumber": "0179ccf8be3b7e605c7b",
    "subject": "C=AT, O=BMSGPK, <IP_ADDRESS>=001001, CN=AT DGC DSC 1",
    "issuer": "C=AT, O=BMSGPK, <IP_ADDRESS>=001, CN=AT DGC CSCA 1",
    "notBefore": "2021-06-02T13:45:24.000Z",
    "notAfter": "2023-06-02T13:45:24.000Z",
    "signatureAlgorithm": "ECDSA",
    "fingerprint": "54e0dde0904f118b15b54d7a3da75049e29d3b63",
    "publicKeyAlgorithm": {
      "hash": {
        "name": "SHA-256"
      },
      "name": "ECDSA",
      "namedCurve": "P-256"
    },
    "publicKeyPem": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNBpX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w=="
  },

I’m not succeeding at decoding publicKeyPem with openssl:
% echo -n 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNBpX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w==' | \
base64 -d | openssl x509 -text
unable to load certificate
140430897976704:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE

% echo -n 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNBpX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w==' | \
base64 -d | openssl x509 -text -inform der
unable to load certificate
139890016028032:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:crypto/asn1/tasn_dec.c:1149:
139890016028032:error:0D06C03A:asn1 encoding routines:asn1_d2i_ex_primitive:nested asn1 error:crypto/asn1/tasn_dec.c:713:
139890016028032:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=serialNumber, Type=X509_CINF
139890016028032:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=cert_info, Type=X509

% echo -n 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNBpX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w==' | \
base64 -d | openssl asn1parse -inform der
    0:d=0  hl=2 l=  89 cons: SEQUENCE
    2:d=1  hl=2 l=  19 cons: SEQUENCE
    4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   13:d=2  hl=2 l=   8 prim: OBJECT            :prime256v1
   23:d=1  hl=2 l=  66 prim: BIT STRING

Any tips?

In Go, it looks like https://golang.org/pkg/crypto/x509/#ParsePKIXPublicKey is the function to use to parse publicKeyPem after base64-decoding. Still not sure how to get the openssl(1) tool to decode them, though :)

% echo -n 'MIIB7zCCAZagAwIBAgIKAXnM+L47fmBcezAKBggqhkjOPQQDAjBEMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQwwCgYDVQQFEwMwMDExFjAUBgNVBAMMDUFUIERHQyBDU0NBIDEwHhcNMjEwNjAyMTM0NTI0WhcNMjMwNjAyMTM0NTI0WjBGMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQ8wDQYDVQQFEwYwMDEwMDExFTATBgNVBAMMDEFUIERHQyBEU0MgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGBNuKiCpnXH0VlIdk6pJZH2ep8jQaV+FR3izMXxZfK5EPGZLtG3Jx+TmV3JJErfrSrPhRmfbSidVbTQ5nnZS+ujbjBsMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUNs2smrjBhuR5Bqxl6teE1x1o2ycwHwYDVR0jBBgwFoAUHyKsHGUWKbTBmLNjb7/dCZ27e3swGgYDVR0QBBMwEYEPMjAyMTEyMTYxNDQ1MjRaMAoGCCqGSM49BAMCA0cAMEQCIDjXHnyzq3sTisMX1uY8xQ2ZqCRL2xmxtYOPhSZ9ZacYAiAqHUMOC7WNgq4h28n31WLc1mMPAYauWslSEwnXC79AGw==' | base64 -d | openssl x509 -text -inform der
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
01:79:cc:f8:be:3b:7e:60:5c:7b
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = AT, O = BMSGPK, serialNumber = 001, CN = AT DGC CSCA 1

Good.

The same AT key in the FR trustlist:
"Is2JtrOJhik="
: {
"serialNumber": "0179ccf8be3b7e605c7b"
,

....

"publicKeyPem": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNBpX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w=="

},
I’m not succeeding at decoding publicKeyPem with openssl:

Correct - as this is a KEY - not an X509 certificate. Your next attempt is exactly right:

% echo -n 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNBpX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w==' |
base64 -d | openssl asn1parse -inform der
0:d=0  hl=2 l=  89 cons: SEQUENCE
2:d=1  hl=2 l=  19 cons: SEQUENCE
4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
13:d=2  hl=2 l=   8 prim: OBJECT            :prime256v1
23:d=1  hl=2 l=  66 prim: BIT STRING

As here you are extracting exactly the public key.
To extract that from your above whole X509 do:
echo -n 'MIIB7zCCAZagAwIBAgIKAXnM+L47fmBcezAKBggqhkjOPQQDAjBEMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQwwCgYDVQQFEwMwMDExFjAUBgNVBAMMDUFUIERHQyBDU0NBIDEwHhcNMjEwNjAyMTM0NTI0WhcNMjMwNjAyMTM0NTI0WjBGMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQ8wDQYDVQQFEwYwMDEwMDExFTATBgNVBAMMDEFUIERHQyBEU0MgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGBNuKiCpnXH0VlIdk6pJZH2ep8jQaV+FR3izMXxZfK5EPGZLtG3Jx+TmV3JJErfrSrPhRmfbSidVbTQ5nnZS+ujbjBsMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUNs2smrjBhuR5Bqxl6teE1x1o2ycwHwYDVR0jBBgwFoAUHyKsHGUWKbTBmLNjb7/dCZ27e3swGgYDVR0QBBMwEYEPMjAyMTEyMTYxNDQ1MjRaMAoGCCqGSM49BAMCA0cAMEQCIDjXHnyzq3sTisMX1uY8xQ2ZqCRL2xmxtYOPhSZ9ZacYAiAqHUMOC7WNgq4h28n31WLc1mMPAYauWslSEwnXC79AGw==' | base64 -d | openssl x509  -inform der -noout -pubkey
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYE24qIKmdcfRWUh2TqklkfZ6nyNB
pX4VHeLMxfFl8rkQ8Zku0bcnH5OZXckkSt+tKs+FGZ9tKJ1VtNDmedlL6w==
-----END PUBLIC KEY-----
Or more complete:
echo -n 'MIIB7zCCAZagAwIBAgIKAXnM+L47fmBcezAKBggqhkjOPQQDAjBEMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQwwCgYDVQQFEwMwMDExFjAUBgNVBAMMDUFUIERHQyBDU0NBIDEwHhcNMjEwNjAyMTM0NTI0WhcNMjMwNjAyMTM0NTI0WjBGMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMQ8wDQYDVQQFEwYwMDEwMDExFTATBgNVBAMMDEFUIERHQyBEU0MgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGBNuKiCpnXH0VlIdk6pJZH2ep8jQaV+FR3izMXxZfK5EPGZLtG3Jx+TmV3JJErfrSrPhRmfbSidVbTQ5nnZS+ujbjBsMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUNs2smrjBhuR5Bqxl6teE1x1o2ycwHwYDVR0jBBgwFoAUHyKsHGUWKbTBmLNjb7/dCZ27e3swGgYDVR0QBBMwEYEPMjAyMTEyMTYxNDQ1MjRaMAoGCCqGSM49BAMCA0cAMEQCIDjXHnyzq3sTisMX1uY8xQ2ZqCRL2xmxtYOPhSZ9ZacYAiAqHUMOC7WNgq4h28n31WLc1mMPAYauWslSEwnXC79AGw==' | base64 -d | openssl x509  -inform der -noout -pubkey | openssl asn1parse
0:d=0  hl=2 l=  89 cons: SEQUENCE
2:d=1  hl=2 l=  19 cons: SEQUENCE
4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
13:d=2  hl=2 l=   8 prim: OBJECT            :prime256v1
23:d=1  hl=2 l=  66 prim: BIT STRING
Which is what yoiu are getting from the FR trustlist if all is well

Just for fun, I made a small web app (no server side components, everything happens on the frontend) that can read and verify EU DCC and UK NHS COVID Pass QR codes:
https://covid-pass-verifier.com/
In case it's useful for anyone the list of certificates (140 as of now) it uses is here:
https://covid-pass-verifier.com/assets/certificates.json
This JSON was generated from the CBOR encoded trust list provided by the Austrian Government's Greencheck app. Example element from the JSON:
{
  "kid": [211,107,221,0,230,63,250,2],
  "crt": [48,130,4,223,48,...,174,204,152],
  "iss": {
    "C": "LU",
    "O": "INCERT public agency",
    "CN": "Grand Duchy of Luxembourg CSCA"
  },
  "sub": {
    "C": "LU",
    "O": "Ministry of Health",
    "CN": "Grand Duchy of Luxembourg DS DCC 3"
  },
  "pub":{
    "x": [228,75,88,108,235,190,70,229,28,...,210,156,153,82],
    "y": [243,124,19,188,214,49,246,...,42,248,201,81,33,63]
  }
}

In theory a EHC could be revoked if some mistake happened. For that there should be revocation lists. I know that at least Switzerland supports a EHC revocation API (https://github.com/admin-ch/CovidCertificate-Apidoc/#api-docs).
Anyone know any revocation list APIs?

Currently the way to revoke is at DSC level.
Revoking at DCC level quickly runs afoul of the GDPR - as the UCI (or anything that specifically pinpoints a DCC) is fundamentally a 'proxy' for a piece of medical information about a citizen.
And publishing lists of such PII's is expressly disallowed by the operators of the gateway (the European Commission). So therefore, at this time, the design does not allow for the revocation at DCC level - only for (whole) DSCs.

Just for fun, I made a small web app (no server side components, everything happens on the frontend) that can read and verify EU DCC and UK NHS COVID Pass QR codes:
https://covid-pass-verifier.com/

@bcsongor Interesting, is the NHS COVID Pass QR code using the same format as the EC one?
And which key are you using to verify it? The 140 ones published by DE and AT do not include any UK certificates.
cheers!

Yes, they seem to be using the DGC spec.
I could only find their public keys, not full certs (pkeys + cert metadata) here: https://github.com/andypandy47/Answer-Digital-Verifier-App/blob/4d79843334c556729ab1c611d02c6244ba8d6f37/VerifierApp.Electron/src/assets/publicKeys.json

@mauimauer great.
I presume KIDs and public keys are enough for QR code verification.

Just for fun, I made a small web app (no server side components, everything happens on the frontend) that can read and verify EU DCC and UK NHS COVID Pass QR codes:
https://covid-pass-verifier.com/
In case it's useful for anyone the list of certificates (140 as of now) it uses is here:
https://covid-pass-verifier.com/assets/certificates.json
This JSON was generated from the CBOR encoded trust list provided by the Austrian Government's Greencheck app. Example element from the JSON:

{

  "kid": [211,107,221,0,230,63,250,2],

  "crt": [48,130,4,223,48,...,174,204,152],

  "iss": {

    "C": "LU",

    "O": "INCERT public agency",

    "CN": "Grand Duchy of Luxembourg CSCA"

  },

  "sub": {

    "C": "LU",

    "O": "Ministry of Health",

    "CN": "Grand Duchy of Luxembourg DS DCC 3"

  },

  "pub":{

    "x": [228,75,88,108,235,190,70,229,28,...,210,156,153,82],

    "y": [243,124,19,188,214,49,246,...,42,248,201,81,33,63]

  }

}

Excellent! Is the source code publicly available? I'm asking for two reasons:

Security through transparency: a DCC is personal data, so one would want to check it's not persisted.
Possibility to extend with executing business rules on top of it.

Great Job!
I'm also interested in its source code. I did start working in past on the something similar for demonstrating the scanning of a QR code. It could be great if we combine our efforts.

https://stackblitz.com/edit/qrcode-scan

I made https://dcc-crosscheck.vercel.app/ - mind that those rules are not the official rules on the DCC Gateway, and no rights can be derived from using that site! Source code here: https://github.com/dslmeinte/dcc-crosscheck

@dslmeinte @bcsongor Should we join forces and start working on a web application just for demonstrating purposes? I believe it will help us communicate rapidly experiences and ideas and get feedback.

Lovely work ! Would be nice to combine the work of you 3 !

@dslmeinte @skounis @dirkx Superb idea, would love to join forces.
I published the source code of my web app and also updated the certificates as it indeed didn't include the UK public keys—sorry for this.
Source code: https://github.com/bcsongor/covid-pass-verifier
(I might have sacrificed some CS best practices on the altar of speed, please look at it from a distance 🙈)
Certificates: https://covid-pass-verifier.com/assets/certificates.json
COVID Pass Verifier is certainly not feature complete and apart from checking the COSE signature there's no other validation against any ruleset. It also lacks support for test and recovery groups, only the vaccination group is supported as of today.

Hello everyone !
I had an issue on sanipasse's automatic certificate fetching from the french backend. The backend usually returns full x509 certificates, with an subject and an issuer that allow knowing where they come from.
But since today, it also returns two additional KIDs for which it provides only an ECDSA public key, without a certificate:

S2V5MVJF (public key MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOFOUp1+SLuaM3NnV+OMZKZOoPg76T7D+vqRCasD0BrRZmlUH2gD+aVlpKvp+u7h8ywTR7T6Z6/iI2Qe6F5begg==)
S2V5MVBSTw==  (public key MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+4ukUdmm9f4AmyQBwTLQFKPPCQj4fP2BpQkIl2hb4p6FxPGDP9z3JkIo2w2xkoxqs2JrTHn2MCdyh3aeyZWD4A==)

I could add these keys to sanipasse too, without certificate information, but I'm a little suspicious. Does any of you know where these KIDs come from and why they are not associated with a certificate ?

Hey @lovasoa, I believe these KIDs and public keys are for the UK certificates. @mauimauer found a project using these keys but I couldn't find the full certificates either and it looks like the repo has been taken down since then. Fortunately I was able to incorporate these (and a couple more UK-related keys) into https://covid-pass-verifier.com/assets/certificates.json just before the repo got deleted/hidden.
I have a UK-issued COVID pass and was able to verify that the public keys match with the signature in the CWT.

Are those the only 2 UK public keys? I thought the file in the original link had more for the same KID. Unfortunately I didn't take a copy of them. Does anyone have them in the format as expected by the dgc verifier app?

For the current Europe-wide list of DCC keys from a Swiss vantage point, see the ch-dcc-keys repo and its data directory.
Because of MITM concerns (as pointed out above by @vaizki ) we check the signature from the Swiss Government (i.e., BIT/Bundesamt für Informatik) that is applied to the exported list of keys and let others check for themselves that this is the official list: Python code to do so is included.

NL does exactly the same - except we publish it into a CDN at https://verifier-api.<acc/test/etc>.coronacheck.nl/v4/verifier/public_keys -- and we sign it the same sort of way as CH.
Extract with curl URL | jq -r .payload | base64 -d. | jq. For efficiency reasons we only expose the public keys (X/Y of the Q on an EC curve), the keyId and class validity. Not the full cert.

@tschudin, @dirkx Thanks a lot for making these public!
In other news, here are the official UK public keys: https://covid-status.service.nhsx.nhs.uk/pubkeys/keys.json — still no certificates unfortunately.

Is there a signature and root certificate from a different source to verify the UK public keys?
Also: I hope this wasn't posted here already and I couldn't find it, but Norway seems to use the same QR-code format except with an NO1: prefix instead of HC1: and these public keys: https://koronakontroll.nhn.no/v2/publickey Although you need a token to access them. More info here: https://harrisonsand.com/posts/covid-certificates/
@dslmeinte @bcsongor Maybe you want to support Norwegian certificates, too? See also my EHC verification Python script that can also be used to just download trust lists (AT, CH, DE, FR, NL, NO, SW, UK) and save them in a CBOR (full x509 certificates only) or JSON format (pub keys+not valid before/after) (both formats defined by me): https://github.com/panzi/verify-ehc It might or might not be of help to you.

@bcsongor the kid field in the UK list is interesting: the values are not according to the EU spec (but serve the purpose, so I see no problem here). The KeyId values provided show that a counter is involved. Here are the UK kid values in hex:
4b6579315245
4b6579325245
4b6579335245
4b6579345245
4b6579355245
4b65793150524f
4b65793250524f
4b65793350524f
4b65793450524f
4b65793550524f

while the EU document "eHealth Network / Guidelines on Technical Specifications for Digital Green Certificates /
Volume 1 / V1.0.5 / 2021-04-21" says:

A.1 The Key Identifier (kids)
The key identifier (kid) is calculated when constructing the list of trusted public keys from DSC certificates and consists of a truncated (first 8 bytes) SHA-256 fingerprint of the DSC encoded in DER (raw) format.

Three days ago @lovasoa  wrote:

But since today, it also returns two additional KIDs for which it provides only an ECDSA public key, without a certificate:
* `S2V5MVJF` (public key

...
I could add these keys to sanipasse too, without certificate information, but I'm a little suspicious. Does any of you know where these KIDs come from and why they are not associated with a certificate ?

As @bcsongor wrote, these seem to be UK keys as they are now accessible via the URL that he gave: https://covid-status.service.nhsx.nhs.uk/pubkeys/keys.json.
The site is only domain-verified via let's encrypt, btw, so this seem to be the most "certification" you can get. Certificate Transparency for governments still needs to be invented ...

See also my EHC verification Python script that can also be used to just download trust lists (AT, CH, DE, FR, NL, NO, SW, UK) and save them in a CBOR (full x509 certificates only) or JSON format (pub keys+not valid before/after) (both formats defined by me): https://github.com/panzi/verify-ehc It might or might not be of help to you.

It would be great if you could contribute the trust list fetch logic to https://github.com/section42/hcert-trustlist-mirror, too, where a number of countries are already mirrored :)

@Csongor -- no need for the certificates - see the specification. They key-id is al that is in the DCC. And all you need to verify the certificate with is the public key. Both of which are, for example, in the UK or NL trust lists / key lists.

On 19 Jul 2021, at 08:26, Michael Stapelberg @.***> wrote:

It would be great if you could contribute the trust list fetch logic to https://github.com/section42/hcert-trustlist-mirror https://github.com/section42/hcert-trustlist-mirror, too, where a number of countries are already mirrored :

@Michael - would there be a nice way to merge this into https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial - so we can check 'anything against any country their idea of something' ?

@michael - would there be a nice way to merge this into https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial - so we can check 'anything against any country their idea of something' ?

I’m not affiliated with that repository, only a user of it :)
I’m using the trustlist mirrors programmatically in https://pkg.go.dev/github.com/stapelberg/coronaqr/trustlist/trustlistmirror
I think a good first step would be to use a common format for all lists (so that you don’t need multiple decoders), but then obtaining the list is as simple as doing an HTTPS request, so it should be easy enough to integrate.

On 19 Jul 2021, at 10:01, Michael Stapelberg @.***> wrote:

@michael https://github.com/michael - would there be a nice way to merge this into https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial - so we can check 'anything against any country their idea of something' ?
I’m not affiliated with that repository, only a user of it :)

Right - but I am - and happy to accept any pull request and/or figure out a way by which the two can levarage a common format or each other.

I’m using the trustlist mirrors programmatically in https://pkg.go.dev/github.com/stapelberg/coronaqr/trustlist/trustlistmirror https://pkg.go.dev/github.com/stapelberg/coronaqr/trustlist/trustlistmirror
I think a good first step would be to use a common format for all lists (so that you don’t need multiple decoders), but then obtaining the list is as simple as doing an HTTPS request, so it should be easy enough to integra.

A pretty common format seems to be a JSON with the KID as the key and then a dict; with one being the public key.
Dw

There's already the format the gateway endpoint would return: https://eu-digital-green-certificates.github.io/dgc-gateway/#/Trust Lists/downloadTrustList
However, in order to use it with WebCrypto having public keys in JWK format instead of certificates/public keys in DER/PEM Format is more useful. My Python script can generate JSON files that are useful for WebCrypto. It's not documented at the moment, though. My format doesn't include a way to verify the trust list against a signature and root certificate, though.
Also to note: IIRC some trust lists only provide public keys, but also include the not valid before/after timestamps. (Hope I don't misremember this.) And other trust lists also provide full trust chains that can to be verified down starting with the country's root certificate (Switzerland).

On 19 Jul 2021, at 08:26, Michael Stapelberg @.***> wrote: It would be great if you could contribute the trust list fetch logic to https://github.com/section42/hcert-trustlist-mirror https://github.com/section42/hcert-trustlist-mirror, too, where a number of countries are already mirrored :
@michael - would there be a nice way to merge this into https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial - so we can check 'anything against any country their idea of something' ?

My script more or less started out with the trivial example, though it's not trivial anymore (and probably should be split to multiple files now). The first thing I added was support for RSA public keys, because the trivial Python example only supports elliptic curves, but there are some countries that use RSA.

You can extract/find the RSA code in
 https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial <https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial> -

It is this commit:
https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial/commit/68ece5f71e0f29ec6391d3e51bb5be905741b1c6

And tested agains the current trust list which has 3 RSA entries.
Dw.

Oh I see. Haven't looked at it after I started writing my own. 😄

There has been a bunch of new public keys without certificate added to the french backend: https://github.com/lovasoa/sanipasse/pull/30/files : S2V5MlJF, S2V5M1BSTw=, S2V5MlBSTw==, S2V5M1BSTw==, S2V5NFJF... Are these all from the UK ?

Seems so yes:
https://covid-status.service.nhsx.nhs.uk/pubkeys/keys.json

@bcsongor the kid field in the UK list is interesting: the values are not according to the EU spec (but serve the purpose, so I see no problem here). The KeyId values provided show that a counter is involved. Here are the UK kid values in hex:
4b6579315245
4b6579325245
4b6579335245
4b6579345245
4b6579355245
4b65793150524f
4b65793250524f
4b65793350524f
4b65793450524f
4b65793550524f

while the EU document "eHealth Network / Guidelines on Technical Specifications for Digital Green Certificates /
Volume 1 / V1.0.5 / 2021-04-21" says:

A.1 The Key Identifier (kids)
The key identifier (kid) is calculated when constructing the list of trusted public keys from DSC certificates and consists of a truncated (first 8 bytes) SHA-256 fingerprint of the DSC encoded in DER (raw) format.

I just noticed that the UK public key IDs are actually ASCII:
Hexadecimal    / Base64       / ASCII
4b65793150524f / S2V5MVBSTw== / Key1PRO
4b6579315245   / S2V5MVJF     / Key1RE
4b65793250524f / S2V5MlBSTw== / Key2PRO
4b6579325245   / S2V5MlJF     / Key2RE
4b65793350524f / S2V5M1BSTw== / Key3PRO
4b6579335245   / S2V5M1JF     / Key3RE
4b65793450524f / S2V5NFBSTw== / Key4PRO
4b6579345245   / S2V5NFJF     / Key4RE
4b65793550524f / S2V5NVBSTw== / Key5PRO
4b6579355245   / S2V5NVJF     / Key5RE

Noticed that when debugging something and Python printed a bytes key ID like so:
>>> b64decode("S2V5M1BSTw==")
b'Key3PRO'

Wonder if that means the *PRO keys are actual production keys and the *RE keys are... what? Research? Are they not to be used in an production environment?

The French trustlist seems to include both kinds of UK keys, but none of the Austrian, Swiss, German, Dutch, Norwegian, or Swedish trustlists include any of those keys.

This is indeed a deviation. Interestingly enough - they have found a 'loophole' - this happens to work - as the KID is just an 8 byte array really. And as long you provide a mapping in your version of the trustlist (rather than expect the verifier to derive it from the original PEM, if any) - it works.

Hi all, I am following this discussion since it started, and I am seeing a problem here:
The trustlist should not only list the public keys, but should also guarantee that the information is complete and correct and only "to-be-trusted" certificates are stored in the trustlist.
Now, we do not have one trustlist but many from different member states, those member states might not have the same view on which certificates are included and which are not (either due to technical reasons or policy/org reasons). Also, certain member states might decide to extend their national trust lists with other certificates for national use cases (in Austria, we planned for that, we wanted to tag the certs in the trustlist as EU-wide and some as AT-Only for national use cases). If someone interprets this information in a wrong way, national certificates (or certificates from other use cases) could then end up in a EU-wide trust relation (in the AT case - if it would have been implemented - this could have meant that certain tests that are only valid for national use cases would end up as EU-trusted tests).
To conclude:

in general, the trustlists of the member states should have the same content for EU-wide trust, but there are multiple reasons why they deviate
If such trustlists are parsed and processed for further use, mistakes might happen and trust relations could be established that were never intended.

Solutions:

central trust list that at least defines the EU wide relations, but we have already been down this road...
for all validators: be very careful on what you trust and talk to the providers of the trustlist in order to get a clear view on their technical/policy view on the trust list. and also bear in mind, if you create your own trust lists for your applications and hand them over to third parties you might include policies/certificates that were specific to a member state/use case...

Yes, I'd whish the trust lists would follow a standard, had some sort of tagging, and would be publicly documented (the German one is). Some trust lists have a way to be verified using a root key, but e.g. in the Austrian case the only place I know where to find that root key is in JavaScript served by the same server as the trust list itself. I do extract and use that root key in my script, but it would be nice if it would be served as-is (not embedded in JavaScript) from some (multiple) other servers. And official documentation would be nice too. Just in case you're somehow involved with the Austrian solution. 😄

@panzi for the austrian solution, this documentation and the procedure for onboarding is just worked out (I think you have my email address, send me a note I can forward you the current PDFs for that), austria will publish the trustlist, the business rules and the value sets for the apps.
for the business rules we will also publish the national AT rules and most likely meta-information for the various profiles (entry, night-clubs, etc.)

Anyone interested in a comparison between which public keys are available in which trust list? The value in the cell is the subject country name as know to the trust list it is from. If the trust list doesn't know that information it is just X.
certs_table.txt
Generated with my verify_ehc.py script: ./verify_ehc.py --certs-table AT,CH,DE,FR,GB,NL,NO,SE (with a few tokens extracted from various apps as environment variables)
Interesting that the Netherlands have a lot of public keys no one else has.

Would be useful to sent this list every week to the interoperability meetings at 12:00 - @Milan - what would the options be to have this reported
About NL - I suspect some systemic thing in how we do the KID (wrong/different). Will get investigated.

@panzi you need to use the production endpoint:
https://unshit.nl/?shit=https://verifier-api.coronacheck.nl/v4/verifier/public_keys
not acceptance:
https://unshit.nl/?shit=https://verifier-api.acc.coronacheck.nl/v4/verifier/public_keys

@ryanbnl Thank you! Fixed.

Thanks. It's an orthogonal issue, but it would be great to see this running against PROD/ACC for as many countries as possible. So we can check that accidents don't happen.

for the business rules we will also publish the national AT rules and most likely meta-information for the various profiles (entry, night-clubs, etc.)

Is this available already?
I was trying to find sources for each country’s covid business rules (as per https://github.com/ehn-dcc-development/dgc-business-rules), but the Swiss endpoint only provides rules for Switzerland.
Maybe we should have a list/mirror for business rules, just like https://github.com/section42/hcert-trustlist-mirror/ is for the trustlist?

@stapelberg You might want to check out https://github.com/eu-digital-green-certificates/dgc-business-rules-testdata which serves as a development/staging area for business rules. Note that these are not synced with the DCC Gateway, precisely to keep it useful for development purposes.
Also possibly interesting: https://dcc-crosscheck.vercel.app/

Thanks, I’m aware of the testdata and my implementation already passes it :)
I’m still interested in getting the live rules from somewhere, though

I noticed that many of the X.509 certificates of various countries seem to be using wrong OIDs in the extended key usage extension. They have an extra .0 component at some point (e.g. <IP_ADDRESS>.<IP_ADDRESS>7.2021.1.1 Vs <IP_ADDRESS>.4.1.1847.2021.1.1).
Countries with these wrong OIDs:
DK, RO, BG, SK, LV, MT, NO, SI, FI, GR

Countries that use the OIDs from the spec:
LI, DE, IS, PL, PT, AT, BE, FR, IE, VA, CY, EE, CZ, HR, LV, LU, IT, LT, SE, CH

The spec: https://github.com/ehn-dcc-development/hcert-spec/blob/main/hcert_spec.md#a4-extended-key-usage-identifiers
Don't know how to pass on that information to the various countries, and don't know if that can be fixed in existing certificates. Thought I post that here just in case there are the relevant people reading this thread.

Don't know how to pass on that information to the various countries, and don't know if that can be fixed in existing certificates. Thought I post that here just in case there are the relevant people reading this thread.

I believe a new published version of https://ec.europa.eu/health/sites/default/files/ehealth/docs/digital-green-certificates_v1_en.pdf should/could address this. This document is still referring to incorrect (with extra 0) Usage Identifiers.

I also found these weird key usages in some of the certificates:
Count OID
     21 <IP_ADDRESS>.<IP_ADDRESS>.2 clientAuth
     20 <IP_ADDRESS>.<IP_ADDRESS>.4 emailProtection

I interpret those as not having any usage IDs and as such fall back to having all three.

I also found these weird key usages in some of the certificates:
  Count OID
     21 <IP_ADDRESS>.<IP_ADDRESS>.2 clientAuth
     20 <IP_ADDRESS>.<IP_ADDRESS>.4 emailProtection

I interpret those as not having any usage IDs and as such fall back to having all three.

by rule, such certificates should be considered as invalid for DCC verification. Isn't it?

These unexpected extended key usage object IDs are all from Spain (C=ES). I don't see any X.509 certificate from Spain that doesn't have these wrong extended key usages.

Ok now whoever is behind the FR trust list (which as the only non-GB one that I know includes the GB public keys) seems to had the idea to fake X.509 certificates for the GB public keys. First they set C=UK (the correct 2 letter country code is GB) and secondly this means that calculating the fingerprint of that fake X.509 certificate gives a key ID that doesn't match what the trust list says it is.
I say fake certificate because the GB trust list only includes public keys, not actual X.509 certificates. Maybe they actually get the X.509 certificates directly from the UK or know a different trust list endpoint? Then it would be the UK itself that uses the wrong 2 letter code for their own country? In any case the mismatching key ID is annoying.
Thought that might be good to know to anyone that also uses that trust list.

Yes, I noticed these strange changes here: https://github.com/lovasoa/sanipasse/pull/42/files
There is also the CN=S2V5M1BSTw== which seems to indicate that they auto-generated the certificate...

Hi, who should I ask for European certificates? Italy etc ..?

You should get in touch with the national health authority of the country you are operating your application in. The national backends will allow to verify certificates from other EU member states as well. @EdossProject

Best to ask the authority in your own country.
And the one Sweden has done is drop dead gorgeous:
 https://dgcg.covidbevis.se/tp/

The dutch one is at:
https://www.npkd.nl/dsc-health.html
https://verifier-api.coronacheck.nl/v4/verifier/public_keys

Dw.

You should get in touch with the national health authority of the country you are operating your application in. The national backends will allow to verify certificates from other EU member states as well. @EdossProject

There is no e-mail or anything else to contact them!

Best to ask the authority in your own country. And the one Sweden has done is drop dead gorgeous: https://dgcg.covidbevis.se/tp/ The dutch one is at: https://www.npkd.nl/dsc-health.html https://verifier-api.coronacheck.nl/v4/verifier/public_keys Dw.

Thanks for listing the links.
The endpoint (https://verifier-api.coronacheck.nl/v4/verifier/public_keys) returns a signature and a payload, how can we get the public key list from the response?

Best to ask the authority in your own country. And the one Sweden has done is drop dead gorgeous: https://dgcg.covidbevis.se/tp/ The dutch one is at: https://www.npkd.nl/dsc-health.html https://verifier-api.coronacheck.nl/v4/verifier/public_keys Dw.

Thanks for listing the links. The endpoint (https://verifier-api.coronacheck.nl/v4/verifier/public_keys) returns a signature and a payload, how can we get the public key list from the response?

The payload is in base64, if you have access to a POSIX terminal:
curl https://verifier-api.coronacheck.nl/v4/verifier/public_keys -g  | jq -r '.payload' | base64 --decode

FYI, the links are also collected on https://github.com/section42/hcert-trustlist-mirror.
Example code for loading all of the trustlist mirror lists (for the purpose of verifying certificates): https://pkg.go.dev/github.com/stapelberg/coronaqr/trustlist/trustlistmirror

Thanks for listing the links.
The endpoint (https://verifier-api.coronacheck.nl/v4/verifier/public_keys https://verifier-api.coronacheck.nl/v4/verifier/public_keys) returns a signature and a payload, how can we get the public key list from the response?

https://www.npkd.nl https://www.npkd.nl/ or the standard chain on most operating systems (CA of The Netherlands).
Dw

Best to ask the authority in your own country. And the one Sweden has done is drop dead gorgeous: https://dgcg.covidbevis.se/tp/ The dutch one is at: https://www.npkd.nl/dsc-health.html https://verifier-api.coronacheck.nl/v4/verifier/public_keys Dw.

Thanks for listing the links. The endpoint (https://verifier-api.coronacheck.nl/v4/verifier/public_keys) returns a signature and a payload, how can we get the public key list from the response?

The payload is in base64, if you have access to a POSIX terminal:
curl https://verifier-api.coronacheck.nl/v4/verifier/public_keys -g | jq -r '.payload' | base64 --decode

Thanks for the clarification.
When I hit the endpoint (https://verifier-api.coronacheck.nl/v4/verifier/public_keys) from the browser or from Postman, it works properly and it returns a response. But when I hit it from the java code, I get the error below:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Does it mean I have to get a certificate? If so, where can I get it from?
https://www.npkd.nl  is giving 403 when I try to download the certificate.

This script shows how to get the Italian trust list: https://github.com/ministero-salute/dcc-utils/blob/master/examples/fetch_certificates.js
Yes, its really one request per trust list entry! Takes over 11 seconds to retrieve the whole list in sequence for me. Since the resume tokens are just counting up from 1 one could request them all in parallel, I guess.

Posting this here since a lot of people were actively participating.
Is anyone aware of a similar public endpoint for the business rules being applied by each respective EU state?
Some countries are actively changing the expiry periods for vaccination certificates, especially the ones given last year. Looking for some central place from where to get these.

Ours are here: https://verifier-api.coronacheck.nl/v6/dcbs/business_rules
The payload is base64 encoded JSON. Otherwise it's the raw data returned by the gateway.

URLs and descriptions of the Austrian rules can be found here:
https://github.com/Federal-Ministry-of-Health-AT/green-pass-overview#details-on-trust-listsbusiness-rulesvalue-sets
The rules are embedded in a CBOR format.

@panzi Nice overview! Do you mind if I backlink to this?

It's not my repo, it's an official repo of the federal ministry of health Austria.

@panzi Understood, and I'll take it as a “yes” :)


faild to train keras model( reapet epoch results )

hi
I want to predict the next number and my dataset is data.xlsx
train on google colab service( runtime type is GPU )
train log image
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras import regularizers

df = pd.read_excel(r'data.xlsx')

dataset = df.values

Y = dataset[:,0]
X = dataset[:,1]

from sklearn import preprocessing
y = Y.reshape(-1, 1) #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
Y = min_max_scaler.fit_transform(y)

x = X.reshape(-1, 1) #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
X = min_max_scaler.fit_transform(x)

from sklearn.model_selection import train_test_split
X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X, Y, test_size=0.2)
X_val, X_test, Y_val, Y_test = train_test_split(X_val_and_test, Y_val_and_test, test_size=0.2)
print(X_train.shape, X_val.shape, X_test.shape, Y_train.shape, Y_val.shape, Y_test.shape)

model_3 = Sequential([
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01), input_shape=(1,)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1, activation='sigmoid', kernel_regularizer=regularizers.l2(0.01)),
])

model_3.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])
hist_3 = model_3.fit(X_train, Y_train,
          batch_size=32,shuffle=False, epochs=10000,
          validation_data=(X_val, Y_val))

Hi,
2 issues that I found with your code.
First, you should fit min_max_scaler only to your training set. After that, you use it to transform your validation and test set.
Secondly, you are trying to predict Y, which is a continuous value. Hence, loss should be defined as mean_squared_error or other loss functions suitable for continuous values. A suitable metric for a continuous output could also be mean square error as well.
This is how I would re-write it:
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras import regularizers

from sklearn import preprocessing
from sklearn.model_selection import train_test_split

df = pd.read_excel(r'data.xlsx')

dataset = df.values

Y = dataset[:,0]
X = dataset[:,1]

Y = Y.reshape(-1, 1) #returns a numpy array
X = X.reshape(-1, 1) #returns a numpy array

X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X, Y, test_size=0.2)

Y_scaler = preprocessing.MinMaxScaler()
Y_train = Y_scaler.fit_transform(Y_train)

X_scaler = preprocessing.MinMaxScaler()
X_train = X_scaler.fit_transform(X_train)

X_val, X_test, Y_val, Y_test = train_test_split(X_val_and_test, Y_val_and_test, test_size=0.2)

X_val = X_scaler.transform(X_val)
X_test = X_scaler.transform(X_test)
Y_val = Y_scaler.transform(Y_val)
Y_test = Y_scaler.transform(Y_test)

print(X_train.shape, X_val.shape, X_test.shape, Y_train.shape, Y_val.shape, Y_test.shape)

model_3 = Sequential([
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01), input_shape=(1,)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1, activation='linear', kernel_regularizer=regularizers.l2(0.01)),
])

model_3.compile(optimizer='adam',
              loss='mse')
hist_3 = model_3.fit(X_train, Y_train,
          batch_size=32,shuffle=False, epochs=10000,
          validation_data=(X_val, Y_val))

Hi,
2 issues that I found with your code.
First, you should fit min_max_scaler only to your training set. After that, you use it to transform your validation and test set.
Secondly, you are trying to predict Y, which is a continuous value. Hence, loss should be defined as mean_squared_error or other loss functions suitable for continuous values. A suitable metric for a continuous output could also be mean square error as well.
This is how I would re-write it:
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras import regularizers

from sklearn import preprocessing
from sklearn.model_selection import train_test_split

df = pd.read_excel(r'data.xlsx')

dataset = df.values

Y = dataset[:,0]
X = dataset[:,1]

Y = Y.reshape(-1, 1) #returns a numpy array
X = X.reshape(-1, 1) #returns a numpy array

X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X, Y, test_size=0.2)

Y_scaler = preprocessing.MinMaxScaler()
Y_train = Y_scaler.fit_transform(Y_train)

X_scaler = preprocessing.MinMaxScaler()
X_train = X_scaler.fit_transform(X_train)

X_val, X_test, Y_val, Y_test = train_test_split(X_val_and_test, Y_val_and_test, test_size=0.2)

X_val = X_scaler.transform(X_val)
X_test = X_scaler.transform(X_test)
Y_val = Y_scaler.transform(Y_val)
Y_test = Y_scaler.transform(Y_test)

print(X_train.shape, X_val.shape, X_test.shape, Y_train.shape, Y_val.shape, Y_test.shape)

model_3 = Sequential([
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01), input_shape=(1,)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dropout(0.3),
    Dense(1, activation='linear', kernel_regularizer=regularizers.l2(0.01)),
])

model_3.compile(optimizer='adam',
              loss='mse')
hist_3 = model_3.fit(X_train, Y_train,
          batch_size=32,shuffle=False, epochs=10000,
          validation_data=(X_val, Y_val))

thanks for your attention.
I change code but the first Epoch to last Epoch is equal you can see  train log
so loss and val loss is very less
and I test my model given just one result
0.051835876 after max min normalize  given this number 4.453738 for all of dataset
import tensorflow as tf
model = tf.keras.models.load_model('number_linear_100.model')
import pandas as pd
df = pd.read_excel(r'C:\Users\Windows\Desktop\test\data.xlsx')

import pandas as pd
df = pd.read_excel(r'C:\Users\Windows\Desktop\test\data.xlsx')

dataset = df.values
acc = 0
iss = 0
listPreLen = 50
for i in range(1,4001,listPreLen):
    Y = dataset[ i : i + listPreLen , 0 ]
    X = dataset[ i : i + listPreLen , 1 : ]

    pre = model.predict(X)
    print(pre[0][0])
# -----------------  results :

0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------
0.051835876
---------------

why given this result?

Take note that RMSE is relative to your Y values. If your Y values are in the range of 0.1, then a RMSE of 0.1 might not be ideal. There is a more detailed explanation here: https://www.kaggle.com/c/competitive-data-science-predict-future-sales/discussion/98629
In addition, I changed the min_max_scaler to a simple normalisation of the data by subtracting the mean and then dividing its standard deviation.
You can look at how I modified your code here:  https://colab.research.google.com/drive/1wEm76N5Xkdp9Sx_jkyN9aEMJjoKCN_BM

Take note that RMSE is relative to your Y values. If your Y values are in the range of 0.1, then a RMSE of 0.1 might not be ideal. There is a more detailed explanation here: https://www.kaggle.com/c/competitive-data-science-predict-future-sales/discussion/98629
In addition, I changed the min_max_scaler to a simple normalisation of the data by subtracting the mean and then dividing its standard deviation.
You can look at how I modified your code here: https://colab.research.google.com/drive/1wEm76N5Xkdp9Sx_jkyN9aEMJjoKCN_BM

I evaluate your colab code this
but given accuracy: 47.27%
how to better that?

@hamidfathi1998 Moving this issue to closed status as there has been no recent activity, in case you still face the error please create a new issue.Thanks!


docs: add typings for SES's global harden()

Simple little hack to get harden well-typed in source files that contain:
/// <reference types="ses"/>

To make this pass eslint (which doesn't know about global harden), you should add the following to eslintrc or package.json:
{
  "globals": {
    "harden": "readonly"
  }
}

@FUDCo any strong desire to fix this, rather than having to specify /* global harden */ everywhere?

I'm not sure if this is the best place to document this, but I've been looking into how to automate the generation of index.d.ts from the JSDoc typing comments, and these are my conclusions so far in summary:

TypeScript cannot consolidate all the typings into a single output index.d.ts output file. I've reached this conclusion after spending hours looking for a way to do it and not finding it, and also from the readme for the package dts-generator which says "the TypeScript compiler doesn’t allow you to actually create a single bundle out of [all the definition files]"

In the TypeScript projects I've worked on in the past, one path is just to let typescript just "do what it does", which is to output a .d.ts file corresponding to every input file, where you would consider the entry point .d.ts file being the one that corresponds to the entry point ts input file (this would be main.js in the case of ses, and the corresponding main.d.ts file). This is the approach I have for Microvium, where the TypeScript entry is ./lib.ts and the corresponding distribution entries are ./dist/lib.js and ./dist/lib.d.ts. There is no index.d.ts. I don't think this approach has many negative impacts, and I'm quite happy with it so far.

Or, if a single consolidated output file (bundle) is required for some package, then one uses a bundler. This can apply to both the distributed JS and the corresponding declaration file: if you want one .js file output, and one .d.ts file output, then you use a bundler that produces these. If memory serves, Webpack does this (taking in a set of JS/TS files, and outputting a single distributable JS file and a single distributable d.ts file). It uses typescript as a plugin. I do not personally like Webpack, nor is it the bundler than SES is using.

I spent some time trying to get TypeScript to work as a plugin to the rollup bundler as part of the ses build pipeline, but was unable to achieve the desired outcome of producing a single, clean index.d.ts. The closest I could get was generating a .d.ts per input file (module), which isn't that great IMO but it would work.

Another option might be to run a separate pipeline in parallel to rollup, using TypeScript to produce definition files as an intermediate build artifact, and then using dts-generator to consolidate these into a single index.d.ts for distribution.

I personally don't like any of these solutions.
Oh, and one other conclusion I've come to from looking at JSDoc comments for typing is that they are ugly and verbose compared to the equivalent pure-typescript syntax. I would personally not choose them for any project since I think they detract from readability rather than contributing to it. But I may be biased here because I've been using pure TypeScript for a long time.

@FUDCo any strong desire to fix this, rather than having to specify /* global harden */ everywhere?

I've got mixed feelings about this.  On the one hand, /* global harden */ is in the file and therefor is more localized -- you don't have the ability of a source file to pass eslint depending on some voodoo happening someplace else.    On the other hand, not having to put the magic comment in a bunch of files makes for a cleaner source base and it makes the source files look the way they will look once harden becomes part of the official language spec.  On the whole, I think I favor the package.json approach more; at the time I put all those /* global harden */ comments in I hadn't realized an eslint config in package.json was an option, and I sort of wish I had.  It's also good that if we shift to the package.json approach we don't have to change everything all at once, we can revise incrementally.

@coder-mike writes:

I'm not sure if this is the best place to document this, but I've been looking into how to automate the generation of index.d.ts from the JSDoc typing comments, and these are my conclusions so far in summary:
[...]
I personally don't like any of these solutions.

I appreciate your investigation, Michael!  Thanks so much for trying the auto-generation direction, and finding that it wasn't fruitful.  You saved me the effort, and for that I'm grateful.
Now I think I'd prefer instead to write a index.d.ts, and turn on // @ts-check for the sources that implement it, so that the types are checked against the sources.  That workflow doesn't fight the tsc, introduce Typescript dependencies or require unnecessary JSDoc.

Oh, and one other conclusion I've come to from looking at JSDoc comments for typing is that they are ugly and verbose compared to the equivalent pure-typescript syntax. I would personally not choose them for any project since I think they detract from readability rather than contributing to it. But I may be biased here because I've been using pure TypeScript for a long time.

I still like JSDoc's zero-build property, and "just ignore the comments if you don't understand them" property too much to want to go back to pure Typescript (which I've been using for about 2 years already).  But of course, pick what works for you in your own projects.

@kriskowal, please review so we can merge before creating the release for @warner.


Unable to pass added request variables from middleware to controller method

This issue is somewhat related to #1024 and #1014, however slightly different.
The Issue
I have a custom middleware class for handling JWT authentication. Essentially all it does is validate the auth token set in the request header and attaches the token and the authenticated user to the request object. This is it below:
// File: app/Http/Middleware/JWTAuthenticate.php

namespace App\Http\Middleware;

use Larapi;
use Closure;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

class JWTAuthenticate
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        $bearerRegex = '/Bearer\\s/';
        $authHeader = $request->header('authorization', null);
        $unauthorizedError = 'Invalid, missing or malformed authentication token.';

        if (!$authHeader || preg_match($bearerRegex, $authHeader) !== 1) {
            return Larapi::unauthorized($unauthorizedError);
        }

        try {
            // TODO: log this authentication
            $token = preg_replace($bearerRegex, '', $authHeader, 1);
            $user = JWTAuth::authenticate($token);
        } catch (JWTException $e) {
            // TODO: log this error
            return Larapi::unauthorized($unauthorizedError);
        }

        $request->request->add([
            'authUser' => $user,
            'authToken' => $token,
        ]);

        return $next($request);
    }
}

Now this works fine when sending requests via curl or Postman, however when running functional tests the middleware fails to attach the additional request parameters, and thus they are unavailable in the handling controller methods. Here is the test that fails:
// File: tests/AuthControllerTest.php

public function testSignOutSucceedsWithValidAuthToken()
{
    $testUserEmail =<EMAIL_ADDRESS>    $testUserPassword = 'Myp4ssw0rd';

    factory(\App\User::class)->create([
        'email' => $testUserEmail,
        'password' => Hash::make($testUserPassword),
    ]);

    $token = \JWTAuth::attempt([
        'email' => $testUserEmail,
        'password' => $testUserPassword,
    ]);

    $this->json('POST', '/auth/sign-out', [], ['Authorization' => 'Bearer '.$token])
        ->assertResponseStatus(200)
        ->seeJson(['success' => true]);
}

Other Information
I also have the below empty UserSignOutRequest  which extends Dingo\Api\Http\FormRequest. This does nothing but added it there just in case I need it there in the future.
namespace App\Http\Requests;

use Dingo\Api\Http\FormRequest;

class UserSignOutRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function messages()
    {
        return [
            //
        ];
    }
}

The handling controller method accepts the above request object. This is where it fails because the signOutUser method is expecting an instance of \App\User but receives null instead, since the user and token never get passed from the middleware to the controller.
public function signOut(UserSignOutRequest $request)
{
    if ($this->repository->signOutUser($request->authUser, $request->authToken)) {
        return Larapi::ok();
    }

    return Larapi::unprocessableEntity();
}

Not sure why these additional params are not getting attached the request object.

Try using get() method on $request. I faced this without dingo/api as well, when using FormRequests.
When using get() method I receive the underlying data. Give it a try.
public function signOut(UserSignOutRequest $request)
{
   if ($this->repository->signOutUser($request->get('authUser'), $request->get('authToken'))) {
       return Larapi::ok();
   }

   return Larapi::unprocessableEntity();
}

@ebbbang Thanks, your suggestion has resolved my issue. Though I'm confused as to why this occurs. Can you shed any light on this?

@nicklaw5 I found an explanation for this issue, have a look at it.
https://github.com/laravel/framework/issues/10791#issuecomment-206198743


Proposal has a security hole

If A creates an proposal to B to change the owner's own permissions to me, then sells the account to C, which changes the owner's permissions to C. When B executes this proposal, the owner's permissions for the account will be changed to A.

 The invalidate action can be called by C to invalidate any proposals that affect B.

Account A adds a proposal in order to update auth, then account A is offline traded to others and the public key is modified, and then proposal is executed causing the public key to be modified again. This will cause serious property damage to the buyer.
like this example
the proposal which named xxtest111111 change the owner key to "EOS7QsF9zA4Yq7ugtVrEFP4UEhBGGnTuhHwaknQJoxp4daih1gUnx"

I think all proposals should expire after ownership changes.

How do we know when ownership changes? I still do not understand why in your example the invalidate action doesn't resolve the problem. The code was specifically modified to stop msig actions from restoring account permissions after an account has been sold. But it is the new owner/exchanges responsibility to call the invalidate action.

I understand what you mean, we will try to solve the problem in this way, thank you


Add a cache system

Add this:
fn handle(request: &Request, cache: &rouille::cache::Cache) -> Response {
    cache.with(|request| {
        Response::text("hello world")
    })
}

The Cache struct contains cache entries.
The with function (whose name may change) analyzes the request and tries to find a corresponding entry in the Cache struct. If one is found, the with function immediately returns the entry. If none is found, the closure is called and the response is stored in the cache.
The function automatically behaves like a "real" HTTP caches by trying to find a Cache-Control header in the response to determine whether it should be cached.

Reference: https://tools.ietf.org/html/rfc7234


Show all ai results

Simple script to show all hidden results in AI training

Hey @D051p0! Thanks for the contribution!
@coffeeneer has a very similar script, that i'd like to point you to https://github.com/coffeeneer/cryptohopper_scripts
Since his repo focuses mostly on AI scripts, I'm going to decline this PR so we don't have overlapping scripts with similar functionality in two different repos.
Please let me know if you have any other ideas! You can also reach me on discord @ricketyMedic.


transformer architecture

any plan to support this type of arch? i.e. vit, swin!

I'm not very familiar with this architecture. I'll look into it and get back to you.

Take a look this, might help.


12129: prevent underscores in form titles

test results on Power BI Desktop Version: 2.102.845.0 64-bit (February 2022) for Windows 10 21H2:

Symbol
Error?
Notes

letters and numbers

only numbers

accented letters

act like letters: allowable even if it's exclusively accented

starting symbol (then letters)

ending symbol (after letters)

start AND end symbol (letters in between)

ONLY symbols
Power BI error
removed/replaced somehow (*1)

emoji

act like symbols: allowable as long as there are also letters

!

"

#

$

%
Power BI error
url %-encoding issue (*4)

&

'

(

formerly disallowed

)

formerly disallowed

*

+

,

-

.

/
Power BI error
removed/replaced somehow (*2)

:

;

<

=

>

?

@

[

\

formerly disallowed

]

^

_
Power BI error
removed/replaced somehow (*3)

`

{

|

formerly disallowed

}

~

explicit messages:

*1: DataSource.Error: OData: The feed's metadata document appears to be invalid. Error: The metadata document could not be read from the message content. InvalidTypeName : The type name 'Collection(NEMO.Group..G1)' is invalid. The type name must be that of a primitive type, a fully qualified name or an inline 'Collection' or 'Ref' type. : (51, 10)

form name was *

*2: Cannot get feed for 'Responses: 2021 :: repeats', as we could not resolve its entity type from the metadata.

form name was 2021 / repeats

*3: Cannot get feed for 'Responses: 2021  repeats', as we could not resolve its entity type from the metadata.

form name was 2021 _ repeats

*4: DataSource.Error: OData: The context URI 'odata/v1/$metadata#Responses:%202021%20%25%20repeats' references the entity set or type 'Responses: 2021 %25 repeats'. However, no entity set or type with name 'Responses: 2021 %25 repeats' is declared in the metadata.

form name was 2021 % repeats


Issue in using molminer

Hey there, When i try to use molminer, i get the following error and Im not sure of it. I have a single pdf file which i wanted to run with ocsr to extract the molecular structure from the pdf.
can some one help me out.
**Cannot perform annotation in ChemSpider: 'chemspider_token' is empty.
Traceback (most recent call last):
File "/home/nx2236/anaconda3/envs/my_new_env/bin/molminer", line 11, in
load_entry_point('MolMiner==1.0.0', 'console_scripts', 'molminer')()
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/click/core.py", line 764, in call
return self.main(*args, **kwargs)
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/click/core.py", line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/click/core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/molminer/cli.py", line 381, in ocsr
result = osra.process(output_formats=["smiles", "inchi", "inchikey"], process_kwargs)
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/molminer/OSRA.py", line 435, in process
stdout, stderr, exit_code = pdf_to_images(input_file, temp_dir, dpi=gm_dpi, trim=gm_trim)
File "/home/nx2236/anaconda3/envs/my_new_env/lib/python3.5/site-packages/molminer/utils.py", line 257, in pdf_to_images
raise RuntimeError("Error when converting PDF to PNG images. Stderr: {}".format(stderr))
RuntimeError: Error when converting PDF to PNG images. Stderr: /home/nx2236/anaconda3/envs/my_new_env/bin/gm.bin: /home/nx2236/anaconda3/envs/my_new_env/lib/molminer/../libtiff.so.5: no version information available (required by /home/nx2236/anaconda3/envs/my_new_env/lib/molminer/libGraphicsMagick.so.3)
/home/nx2236/anaconda3/envs/my_new_env/bin/gm: line 6:  4341 Illegal instruction     (core dumped) LD_LIBRARY_PATH=realpath $DIR/../lib/molminer $DIR/gm.bin ${@:1}

Hello,
there is probably some problem with libtiff or GraphicsMagick.
Can you run in your molminer virtual environment: $ gm convert -density 300 <pdf_file.pdf> +adjoin -trim -quality 100 output-%d.png

OK, so there is probably a conflicting version of libtiff which is installed as a dependency of some package which molminer depends on. OSRA is compiled against libtiff which is packaged with molminer.
As a temporary solution, run this in your molminer venv: $ conda uninstall libtiff --force
It works for me and I hope it will also work for you. Unfortunately, molminer is not my priority anymore, but I hope I will find some time to fix this issue directly in the conda recipe.


Data refresh script creates just one variable for FAOSTAT

We need to create one variable for each indicator. Each FAOSTAT csv files contains multiple indicators.  The Element column specifies the variable, the Item is main subject, and the Value column is the numeric value.
 We should switch to templates.
Also, these FAOSTAT files are huge. We should preprocess to just keep Ethiopia rows. If that is still to big we should only import indicators listed in Issue #77 .

Switching to templates


Identification of form and button type in the click source

Is your feature request related to a problem? Please describe.
In many pages, there are more than 1 form, especially with search form in the header. Checking which form the user interacted with is difficult in those situations. Adding an id (or classname) of the form can help in identifying the form which user have interacted with.
Also the button type of the button element is not present in the selector, especially inside forms. That will help in identifying if a submit button was clicked or not, in cases where users have prevented the default form submit action (leading to non tracking of form submits)
Describe the solution you'd like

Adding id/classnames in the sourceSelector for form tag
Adding buttonType in the button selector for form tag

Describe alternatives you've considered

It is difficult to identify which form the user interacted/submitted with just by looking at the source selector as (form .button).
looking at the source of the page to identify which button was clicked, and that works only if there is 1 button in the form.

Fixed with https://github.com/adobe/helix-rum-enhancer/pull/293


use ascii instead of utf-8

writeEarlyHints on node uses ascii instead of utf-8. in node the strings get actually also validated by a regex. That regex is imho validating implicitly that it is ascii. Maybe we need to url_encode href to be sure we dont send garbage?

Checklist

[ ] run npm run test and npm run benchmark
[ ] tests and/or benchmarks are included
[ ] documentation is changed or added
[ ] commit message and code follows the Developer's Certification of Origin
and the Code of conduct

closing in favor of #5


[BUG] : Outdated Twitter icon

Prerequisites

[X] I am an Open Source Contributor
[X] I checked to make sure that this issue has not already been filed

Description
The twitter icon in the contact section is outdated and needs to be changed.
Screenshots

Code of Conduct

[X] I follow Contributing Guidelines of this project.

Proceed @SulagnaKundu

@SulagnaKundu Provide your PR by today else you will be unassigned

Hello @Rakesh9100   , I would like to work on this issue under JWOC.

Go ahead @thatguywhocode

Hey @Rakesh9100 , i solved the bug and created the pr under JWOC.

@Rakesh9100 I would like to work on this under JWOC


Proposal for new terms

I would like to propose adding the following terms:

Agile/Agile Software Development
CaaS, PaaS, IaaS, SaaS, FaaS
Serverless
Docker
Site Reliability Engineering

Definitions of Serverless, SaaS, FaaS, IaaS are already available.

@iamNoah1 sorry about the slow response! I believe that with the new glossary.cncf.io site we're deprecating the pdf. Regardless, we'd love to see some PRs and issues for the terms you listed with the possible exception of docker as I'm not sure it requires a definition.

@JasonMorgan no worries. Thanks for the feedback, I will open PR(s) to add the terms that are not already existing :)

Hi @iamNoah1, wanna work on any of the other terms you suggested that haven't been addressed yet? Also, if you could create one issue per term, that'd be great. Thank you! Catherine

Hei @CathPag, yes I will. I think only SRE is not addressed yet. Will create an issue for it :) and close this one.

obsolete through #261 and #262


Strange issue with Scratch in loop

len show that .Data.Page contains 259 pages. But the range loop iterates only 22 times (only 22 wtf? are rendered). If I remove Scratch related calls, I got 259 wtf?. What is going on here and how to fix it?
{{ len (where .Data.Pages "Section" "article").ByDate.Reverse }}
{{ range (where .Data.Pages "Section" "article").ByDate.Reverse }}
  wtf?
  {{ $.Scratch.Add .Params.category 1 }}
{{ end }}

Background: I have custom Param called category. Now I want to list 2 Pages for every category sorted by Date. Something like this:
{{ range (where .Data.Pages "Section" "article").ByDate.Reverse }}
    {{ if lt ($.Scratch.Get .Params.category) 2 }}
      {{ $.Scratch.Add .Params.category 1 }}
      <div class="column">
        {{ .Render "list-item" }}
      </div>
    {{end}}
{{ end }}

Thanks for getting in touch, but it feels like this is a question  that would be better suited to the Hugo Discussion Forum.  We prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug. You may also find the answers you search for in Hugo Documentation.

{{ range (where .Data.Pages "Section" "article").ByDate.Reverse }}
  wtf?
{{ end }}

iterates 259 time (this ist correct) but this
{{ range (where .Data.Pages "Section" "article").ByDate.Reverse }}
  wtf?
  {{ $.Scratch.Add .Params.category 1 }}
{{ end }}

only 22 times. Sounds like a bug 💯


Ensure highlighting matches the filter method chosen

This is the second of my PRs. My autocompleters needed to use the Awesomplete.FILTER_STARTSWITH method for filtering. However, when I set that as the filter method, I found that the highlighting still highlighted matches anywhere in the string. In short, the default item function didn't respect the filter method.
I solved this problem by creating a _.RE variable which is set inside of the two filter methods and is re-used inside the default item method.
I do see one setback to this approach, however. In order for a user to override either the filter method or the item method without overriding the other and retain matching behavior, they will need to know about and use this Awesomplete.RE lambda. This could be solved simply via documentation, but I'm not certain how flexible this approach is, or whether you would like this. Thus why I don't currently have updated docs in the PR.
I believe that we need a simple way to ensure that the filter method and the item method are working in parallel, but I'm not yet convinced this is the best approach. So, consider this PR an initial attempt and a space to discuss other/better approaches.
stephen

Of course, I guess the simplest option would be to add something like a regexp or matcher option to the o hash which both item and filter look to. Making it explicit in the options hash would make it simpler to document how best to override those methods.

Hi there,
Thanks for contributing!
Agreed this is confusing, though the proposed solution is a bit awkward.
Question: If you’re only matching at the start, why do you even need the highlighting? Why not just add some CSS to set the background of <mark> to none?

That is a simple and reasonable solution to my particular issue; however, the larger architectural issue does remain. In short, you cannot override only item or filter and have sensible behavior. You either have to override neither or both. The conceptual solution is to have a match method that underlies both. However one determines if input matches text, that logic should be used in filtering and in item rendering.

Agreed on your assessment of the problem. However, this solution is having multiple Awesomplete instances modify a single static Awesomplete.RE variable. I’m not sure how this is either conceptually elegant or simple & reasonable...


Add hash to production bundles file name

https://webpack.github.io/docs/long-term-caching.html#option-1-one-hash-for-the-bundle
Add this feature can prevent caches from user's browser block our latest bug fix.

Hi @EcutDavid,
that would be a nice addition. Will think about it and eventually include it in the default. Thank you!


Feature proposal: sftp context by git branch

Just a proposal, maybe you like it
Example config
[
  {
    "context-git-branch": "master",
    "remotePath": "/remote/public_html",
    (...)
  },
  {
    "context-git-branch": "dev",
    "remotePath": "/remote/staging",
    (...)
  }
]

So when switching branches, the sftp context would change as well

+1 !

This could be done by githooks.

Thanks! I'm now using different config files, like this
.vscode/sftp-live.json
.vscode/sftp-dev.json
.vscode/sftp.json

And depending on the context I just paste the content of one of the first files into sftp.json. So probably something like cp .vscode/sftp-{branchname} .vscode/sftp.json

I think the context should just be a name to be honest, like jetbrains does on their IDEs.. you put a name to a context with a remote path, then when you want to upload/download, tu select the context based on the name. and in addition to that u can set a default context for autoupload

Thanks! I'm now using different config files, like this
.vscode/sftp-live.json
.vscode/sftp-dev.json
.vscode/sftp.json

And depending on the context I just paste the content of one of the first files into sftp.json (much more robust than renaming all the time)
So probably in the post-checkout-hook it would only need something like cp .vscode/sftp-{branchname} .vscode/sftp.json

I found that using Ctrl+Shift+P to upload project wouldn't know the current sftp.json setting, how could I update the config ?

I found that when I using Ctrl+Shift+P to upload project, it wouldn't know the current sftp.json setting, how could I update the config ?

I guess that feature isn't available. I still copy & paste the content of the "note" json (e.g. sftp-dev.json) to the wired sftp.json file when I need to

Not depending on the git branch, but here's a working example for SFTP with multiple profiles (on mac with pubkey, same server).
{
    "name": "multi profile",
    "protocol": "sftp",
    "host": "server.com",
    "port": 123,
    "privateKeyPath": "/Users/mac_username/.ssh/id_rsa",
    "uploadOnSave": true,
    "username": "hosting_username",
    "agent": "$SSH_AUTH_SOCK",
    "passphrase": true,
    "profiles": {
        "dev": {
            "name": "dev",
            "remotePath": "/path/to/dev/"
        },
        "live": {
            "name": "live",
            "remotePath": "/path/to/prod/"
        }
    },
    "defaultProfile": "live"
}

Switch with cmd+Shift+P `SFTP: Change profile`
Control at the bottom of vscode:

![image](https://user-images.githubusercontent.com/1446443/66384704-891e4b00-e9bf-11e9-8236-91c34d66f3dc.png)


how to set dqlite config?

can I set the dqlite config about heartbeat-interval and election-timeout like etcd?

I am sorry @logici these parameters are not exposed.

thanks for your reply. But why these parameters are not exposed? Or it is in plan? how I can find these parameters value?

Hi @logici
These parameters can be configured by interacting with the dqlite database directly. MicroK8s does not support any convenient methods to change these parameters, but we do consider this issue to be a feature request. If more people are interested, please respond to this issue to help us prioritize :)
Meanwhile, contributions are always welcome. If anyone is interested to pick this up, this requires work in k8s-dqlite, where a config file is read and options are appended to the default dqlite config, in a fashion similar to this.


Should we publish this under the @google npm scope?

I rather like the idea of keeping all of our npm modules under the @google scope.  Do folks have any opinions on moving us over there?

Mixed feelings about calling this @google/something on npm. That may make people think that this is specific to google projects, while it is a generally usable utility. This is the same rationale why eventid and gts are not in the Google npm scope.
I am in favor of some renames though. The term post-install-check doesn't seem descriptive to me. A better name would be something like ts-install-check.

This has been addressed.


Preserve custom response headers from the original image

I am currently using HTTP response headers such as unique id and via header to track the request process.
However, weserv will discard all HTTP response headers after obtaining the original image and regenerate all HTTP headers by itself.
I hope to be able to retain headers other than the HTTP response headers that must be changed (such as Content-Length, Date, etc.), as well as some headers that may leak privacy (such as Set-Cookie), to facilitate request process tracking and debugging.

This is indeed by-design to strip all headers. Are you using an self-hosted version, or the public service? For self-hosted you might be able to script something to add them back in.

I'm using a self-hosted service, but there doesn't seem to be any existing option to configure passthrough response headers. What does script mean?

For the same reasons we do not pass any information to the origin server, we also do not retain (or internally parse) any response headers from the origin server.
The only meta information retained from the original image is its size, which does not necessarily originate from the Content-Length header, as upstream servers are allowed to omit this.
https://github.com/weserv/images/blob/947dbc4ef817509620f678d9186cb6c097957687/ngx_conf/imagesweserv.conf#L58
Feel free to use the provided source code to host your own solution, which you can customize to suit your needs. For example, if you only need to process images from a single domain, you can use nginx's proxy_pass directive in combination with the weserv filter directive. For more details, see: https://github.com/weserv/images/issues/314#issuecomment-952012562.

Additionally, you can refer to the ngx_http_proxy_module for guidance on implementing this behavior within the weserv proxy directive. See the following links for comparison:
https://github.com/nginx/nginx/blob/release-1.27.1/src/http/modules/ngx_http_proxy_module.c#L1900-L1941
and:
https://github.com/weserv/images/blob/947dbc4ef817509620f678d9186cb6c097957687/src/nginx/http.cpp#L467-L515
After that, the various response header fields ought also to be available via the $upstream_http_<NAME> variables.


Update readme (badges).

I added the codecov badge which will automatically update our (for now just backend) coverage. I deleted the frontend badge because it creates confusion. @lasaeren Is it possible to generate a xml file for the frontend tests? This way codecov can merge the two percentages in the codecov badge.

@henricattoire maybe https://vitest.dev/config/#reporters


Added support for segment comments

This adds the ability to write/read comments of SegmentItems.

Coverage remained the same when pulling 44098892d326086606611a0701041f8c193a7d8a on CPInc:segment-comments into cfbf54ad01bbf5034403675d3e4f71535a69d5af on sethdeckard:master.

Thank you!


Frontend Socket start of implementation

What does this implement/fix? Explain your changes.
Reworking the GM to handle it's own socket and to decouple the AI from the GM
Does this reference any currently open issues?
A2.4
Types of changes
What types of changes does your code introduce?
Put an x in the boxes that apply

[ ] Bugfix (non-breaking change which fixes an issue)
[X] New feature (non-breaking change which adds functionality)
[ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist
Put an x in the boxes that apply. You can also fill these out after creating the PR. This is simply a reminder of what we are going to look for before merging your code.

[X] I have linted my code and I have run tests locally that pass
[ ] I have added tests that prove my fix is effective or that my feature works
[X] I have added necessary documentation

Any other comments?
…

References #152


Rocket Chat Linux Desktop can not get any notification and open any link

Hi
I am working on CentOS Linux release 7.7.1908 (Core), and currently using  v2.17.2 Rockchat Linux version.
And I find that I can not get any notification at Linux, but I can get notifications at Windows environment. The desktop notification test function does not work neither.
The second problem is I can not open any link at Linux, it just no feedback, do I need to tell Rocket chat how to start a  browser session? And by the way I can open link at Win and Web environment.

@dusatvoj Does it still happen in version 2.17.5?

I'm running 2.17.8 and it's still not working.

Running the 2.17.11 solved the problem. Thanks!


MythicMobs Module error

(Required) What is your Quests version 3.2.4/ build 255 ?
(Required) I am not sure why but sometimes the console is getting filled with this:https://pastebin.com/es11j2TK
(Optional) This module installed: https://www.spigotmc.org/resources/mythicmobs-quests-module.7261/

https://pastebin.com/XifuhVeQ
Duplicate issue

Duplicate of #265
Use the latest dev build, released today.