rust-italia / dgc Goto Github PK
View Code? Open in Web Editor NEWA parser and validator for the EU Digital Green Certificate (dgc) a.k.a. greenpass
Home Page: https://github.com/rust-italia/dgc
License: MIT License
A parser and validator for the EU Digital Green Certificate (dgc) a.k.a. greenpass
Home Page: https://github.com/rust-italia/dgc
License: MIT License
It seems that in some certificates the field issued_at
of DgcCertContainer
can be a float (see ES/2DCode/raw/1501.json
for an example).
This seems to be compliant for the official validator.
First of all, it would be convenient to have a way to distinguish between test, recovery and vaccine data through an enum. This might look like the following code:
#[derive(Debug)]
pub enum CertData<'a> {
RecoveryData(&'a Recovery),
TestData(&'a Test),
VaccinationData(&'a Vaccination),
}
Once we have this, DgcContainer
could implement a method like get_first_cert()
which might work as follows (untested):
impl DgcContainer {
pub fn get_first_cert(&self) -> Option<CertData<'_>> {
for (_, certs) in self.certs.iter() {
if let Some(v) = certs.v.first() {
return Some(CertData::VaccinationData(v));
}
if let Some(t) = certs.t.first() {
return Some(CertData::TestData(t));
}
if let Some(r) = certs.r.first() {
return Some(CertData::RecoveryData(r));
}
}
None
}
}
A structurally valid Dgc should contain only one entry, so we can use this method to extract that easily.
Hi!
Thanks for your work :-D
It would be useful to add a notice in the README specifying that the usage of software that reads and decode the DGC might be limited by national laws. For example, in Italy the "VerificaC19" app is the only generally available software authorized by the GPDP ("Garante per la protezione dei dati personali", the italian authority supervising data protection and processes) and the government 1.
While this library can be used in a lot of legal ways (e.g. research, special authorizations, etc), I think that it's wise to warn potential users about the fact that local laws might prohibit them to implement such "dgc readers" software.
Be safe :-)
We should use dcc-quality-assurance for our tests.
See the python script to parse the PNGs files
If we aim to get formal approval from Italian authorities as a good library to use for DGC parsing and validation I think it could make sense to implement functionality for easily populating a Trustlist
using the Italian APIs.
It seems that the 2 main endpoints for that are:
It would be nice to be able to do something like this:
let cert_data = "HC1:NCFOXNEG2NBJ5*H:QO-.OMBN+XQ99N*6RFS5YUCH%BM*4ODMT0NSRHAL9.4I92P*AVAN9I6T5XH4PIQJAZGA2:UG%U:PI/E2$4JY/KB1TFTJ:0EPLNJ58G/1W-26ALD-I2$VFVVE.80Z0 /KY.SKZC*0K5AFP7T/MV*MNY$N.R6 7P45AHJSP$I/XK$M8TH1PZB*L8/G9YPDN*I4OIMEDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+S/15A+2XEN QT QTHC31M3+E3+T4D-4HRVUMNMD3323623423.LJX/KQ968X2+36/-KKTC 509UE1YH/T1NTICZUI 16PPT1M:YUKQU7/EAFQ+JU2+PFQ51C5EWAC1ASBE/V9.Q5F$PYBEO.0:E5 96KA7N95ZTM L7HHP4F5G+P%YQ+GONPPCHPMR73SOM352Q4FIR L7 SP5.PDSOSNQKIR%*O* OUKRTSOL0PNLE.$FW2I9R7P3LEERQ2Q$CS8-QL4W.X0WB0/89-M7O9F:4AV0OGXP7MEKC53WRXY41A1/:R/J9URTB%LKXAD-OAZ0GA5%UCI/I910G-8H3";
let cwt: dgc::Cwt = cert_data.parse().unwrap();
This will be possible by implementing the FromStr
trait on Cwt
.
capi
guarded module.cbindgen.conf
with the minimal featuresREADME.md
Once this PR is landed, we can remove our extension trait and directly use Value::into_
methods.
Blocked by enarx/ciborium#34
Right now the library only validates a certificate based ONLY on the status of the signature. In reality a certificate can be considered invalid even if the signature is validated correctly.
As far as I understand there are several other factors that we should support in terms of validation:
DgcContainer
struct already collects these timestamps but we offer no easy way to check the current time against them.In the context of this issue I think it will important to figure out an ergonomic API that:
Maybe we could have a dedicated CertificateValidity
struct that can contain various fields like this:
pub struct CertificateValidity {
signature: SignatureValidity,
time: TimeValidity,
business_rules: BusinessRulesValidity
}
SignatureValidity
, TimeValidity
and BusinessRulesValidity
could be enums that can encapsulate all the different state of validation that is relevant for them. For instance:
pub enum TimeValidity {
Valid,
NotValidYet,
Expired
}
Finally we could have a is_valid()
method on the CertificateValidity
struct that simply returns true
or false
if all the conditions are satisfied or not...
In order to make the crate fully usable in Italy, we need to add support for:
For the second and the third points, more information can be found in the ScanMode documentation.
It is still unclear where it is possible to found detailed information about the exemptions (maybe this could be helpful?).
There are a few json files that fails for strange reasons.
For instance, as discussed in #33, there are some public keys that use ECDSA-P384 signing algorithm, even if the alg
field in the fields indicates a RSA-PSS-SHA256
signature.
Maybe it is something that we cannot really fix, but at least we have a tracking issue to refer.
It would be nice to have the Display
trait implemented for most of the structs.
This will make it easier to visualise the data in a descriptive format.
Add more examples in the documentation (README) and add proper programmatic documentation
The current implementation only supports EC P-256 signatures.
Some test certs use RSA (example data CH/2DCode/raw/1.json
).
Specification is scattered a bit around, but this is probably the best i could find: https://ec.europa.eu/health/sites/default/files/ehealth/docs/digital-green-certificates_v1_en.pdf
Pagg 5-6 say:
The Signature Algorithm (alg) parameter indicates what algorithm is used for the creating the
signature. It must meet or exceed current SOG-IT guidelines.
One primary and one secondary algorithm is defined. The secondary algorithm should only be
used if the primary algorithm is not acceptable within the rules and regulations imposed on the
implementor.
However, it is essential and of utmost importance for the security of the system that all
implementations incorporate the secondary algorithm. For this reason, both the primary and
the secondary algorithm MUST be implemented.
For this version of the specification, the SOG-IT set levels for the primary and secondary
algorithms are:
- Primary Algorithm: The primary algorithm is Elliptic Curve Digital Signature Algorithm
(ECDSA) as defined in (ISO/IEC 14888–3:2006) section 2.3, using the P–256 parameters as defined in appendix D (D.1.2.3) of (FIPS PUB 186–4) in combination the
SHA–256 hash algorithm as defined in (ISO/IEC 10118–3:2004) function 4.This corresponds to the COSE algorithm parameter ES256.
- Secondary Algorithm: The secondary algorithm is RSASSA-PSS as defined in (RFC 8230) with a modulus of 2048 bits in combination with the SHA–256 hash algorithm as
defined in (ISO/IEC 10118–3:2004) function 4.This corresponds to the COSE algorithm parameter: PS256
Based on https://github.com/ehn-dcc-development/ehn-dcc-schema/blob/release/1.3.0/DCC.Core.Types.schema.json#L17-L63 it looks like that only the field fnt
is mandatory in the DgcCertName
struct. We are currently assuming fn
is mandatory too which leads to failing tests.
We should change DgcCertName
fn
to be an Option<String>
Every country publishes country-specific rulesets (also called business rules) that are used to determine if a certificate is valid on a given country based on national rules.
E.g. It's likely that in Italy "negative test certificates" won't be considered valid for most activities.
These rulesets are somewhat documented here: https://github.com/ehn-dcc-development/dgc-business-rules
For Italy you can find the current ruleset at the following URL: https://get.dgc.gov.it/v1/dgc/settings
Interesting enough there is even a black list encode as a rule!
There are some tests (at least ES/2DCode/raw/1001.json
, ES/2DCode/raw/1002.json
and ES/2DCode/raw/1003.json
) that fail the signature validity.
These tests were previously related to a missing support for floating points for two fields in DgcCertContainer
(#3), maybe the failure is related to that in some way?
Test file common/2DCode/raw/CO20.json
fails because the KID is saved in the unprotected header rather than in the protected header of the COSE payload.
Apparently this is perfectly valid behaviour and the signature should use the KID in the unprotected header (if there is none in the protected header).
test data:
{
"CBOR": "bf6376657265312e322e31636e616dbf62666e754d7573746572667261752d47c3b6c39f696e67657263666e74754d5553544552465241553c474f455353494e47455262676e684761627269656c6563676e74684741425249454c45ff63646f626a313939382d30322d3236617481bf62746769383430353339303036627474684c50363436342d34626e6d76526f636865204c696768744379636c6572207150435262736374323032312d30322d32305431323a33343a35365a627472693236303431353030306274637754657374696e672063656e746572205669656e6e61203162636f624154626973781b4d696e6973747279206f66204865616c74682c2041757374726961626369783155524e3a555643493a30313a41543a42353932314133354436413044363936343231423345323436323137383239372349ffff",
"COSE": "d28440a204483248bc38d9547e630126590154a4041a6092dd20061a60903a2001624154390103a101a4617481a962736374323032312d30322d32305431323a33343a35365a627474684c50363436342d34626e6d76526f636865204c696768744379636c657220715043526274637754657374696e672063656e746572205669656e6e61203162636f624154626369783155524e3a555643493a30313a41543a42353932314133354436413044363936343231423345323436323137383239372349626973781b4d696e6973747279206f66204865616c74682c20417573747269616274676938343035333930303662747269323630343135303030636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e322e3163646f626a313939382d30322d323658405272eaa283596735aac167d1f8ae95253c70cbcb60c98006514ee02ca315f83a35dd2b7983b7980ecec645cef705b1913aac525034db103e2668d1c6f31e5ee8",
"PREFIX": "HC1:NCFRY37C8OJ2500S6C+QDGTSB4J7F6T6VKOA7+4RZQY8AGTJF.R5LIE05*ICA79*5PB7UQYES-DT$D+95E:V5E5D7S8OJEG4203+AF-G8%E1LJF-A5UR2-+3GNQOYT:CFBPU5Y74-76RLFVT7UQI8DNH7KPDAT6GQJ1*7YL0AXM6.4+77%4IKDT-L5CH2H19 OCHBV96668FDO%I8UT2ITE8Y74$DC3E4H82EGBWMH-PFG64EK:UIT/ANQMGI6N0RE9EM:S/ZKV.AGO0: CW5QPHB7I2*T4434AE2BDU5$19RMVLD52PEKCN*O*2M0HI%VE3BLU3B5:8E/8GKCQA1QAD6ZG4/O4Z677HN0BFURLKKO3PGDQ1YAQCVDF7I+V:$5G 2 JQDG0YLK984QJN4C1CJERZGSZO-M2YM69-QS$M6DGMSS*1D7ZN*%M/-M1435KQ%SKJ2KWOMF%2+G1JOSVWO7OV5.I$*OBV61YP**2DK0*AJ:WHB1L-4CI%DBC5V8G/BIJ36F T2YUPEWBOKW6J2AV/8CNX5JBS1C9PCQT28+4O5GF8.RWTV/SVO$U$/V/HJ/6TZ.RLCUPLFQPT 35COVGPUTRA+1I/FP3VP DT:XQF08EFUHRVZ$2Y%I",
"TESTCTX": {
"VERSION": 1,
"SCHEMA": "1.0.0",
"CERTIFICATE": "MIIBVzCB/6ADAgECAgRzLoFUMAoGCCqGSM49BAMCMBAxDjAMBgNVBAMMBUVDLU1lMB4XDTIxMDUwMzE4MDAwMFoXDTIxMDYwMjE4MDAwMFowEDEOMAwGA1UEAwwFRUMtTWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQkI7eQFjMDlzlZE76ey3MxeRRXqe19Gz5zI534UOGwz0uk3rC1lzMRKFjlMYqi/vEbZerv5xjysRnzhyo1P/P9o0cwRTAOBgNVHQ8BAf8EBAMCBaAwMwYDVR0lBCwwKgYMKwYBBAEAjjePZQEBBgwrBgEEAQCON49lAQIGDCsGAQQBAI43j2UBAzAKBggqhkjOPQQDAgNHADBEAiBS0ew1ZTfhrMdiOqGuSiRAe9kpg9jNZoHBICd0rAEjvQIgeFUhq00LEJHST3StBaww1NrZpEyYgh7XeC5ZK7UbRDE=",
"VALIDATIONCLOCK": "2021-05-03T18:00:00Z",
"DESCRIPTION": "VALID: KID in protected header correct, KID in unprotected header correct"
},
"EXPECTEDRESULTS": {
"EXPECTEDVERIFY": true
}
}
We are currently taking a mixed approach to field naming:
1
is converted to issuer
in DgcCertContainer
)fn
rather than something more descriptive like family_name
.I'd like to go for a descriptive approach, leaving to serde
the responsability to rename the fields back to their original format in case we want to re-serialise the structs (for instance to JSON).
As an example (suggested by @dodomorandi in #27):
struct x {
#[serde(skip_serializing_if = "Option::is_none", rename = "fn")]
pub family_name: Option<String>,
}
In the example above we are deserialising the field fn
to family_name
(better api for the user) but we tell serde
to serialise it back to fn
if we have to serialise the struct again (e.g. to JSON).
Since this will be a significant breaking change, I'd like to mark this for 0.1.0
. But I suggest it's tackled as part of #6!
Add the following examples in the examples
folder:
der
-encoded data and from certificatesThis implementation is currently using a fork of ciborium
called ciboriumvalue
containing some changes that haven't been published already by the ciborium
team (e.g. support for easily parsing CBOR tags) + changes proposed in enarx/ciborium#25.
Once this PR is merged and a new version of ciborium
is released this project should update the dependencies to the latest version of ciborium
and remove ciboriumvalue
.
Blocked by enarx/ciborium#25
Only a portion of the official testing data has been used to test against the library.
The current version of the testing data has been already loaded in the repository but most of the test cases are still commented.
Inserire all'interno delle richieste verso le API l'apposito header User-Agent nella forma
User-Agent: <sdk>-<sdk-technology>/<sdk-version>
È possibile omettere -<sdk-technology>
se la tecnologia è già specificata nel nome (ad esempio verificac19-sdk-php).
Ad esempio nel caso verificac19-sdk
per Node.js lo User-Agent sarà
User-Agent: verificac19-sdk-node/0.9.3
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.