Coder Social home page Coder Social logo

rust-italia / dgc Goto Github PK

View Code? Open in Web Editor NEW
26.0 5.0 11.0 3.53 MB

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

Rust 99.61% Shell 0.39%
greenpass dgc rust rust-crate rust-library parser validator certificate green eu

dgc's People

Contributors

allevo avatar dodomorandi avatar garro95 avatar lmammino avatar lu-zero avatar nappa85 avatar rimpampa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

dgc's Issues

C bindings

  • Make sure the current API is set (pending @dodomorandi rework)
  • Write a capi guarded module.
  • Add cbindgen.conf with the minimal features
  • Document how to install it in the README.md

Remove ciborium fork from dependencies

This 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

Inserire l'apposito header User-agent nelle richieste verso le API

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

Add more examples

Add the following examples in the examples folder:

  • How to validate the signature of a certificate
  • How to create a trustlist using keys from der-encoded data and from certificates
  • How to create a trustlist from an official dgc trustlist API
  • How to expand a result using the matching data in the official valueset

Implement `FromStr` for `Cwt`

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.

Add support to verify RSA signatures

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

Support tests ES/2DCode/raw/100[123].json

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?

In-depth validation of certificates

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:

  • Signature validity: already supported ✅
  • Certificate emission time and expiry time. The DgcContainer struct already collects these timestamps but we offer no easy way to check the current time against them.
  • Business Rules (or country-specific rules): see #19 for dedicated issue.

In the context of this issue I think it will important to figure out an ergonomic API that:

  1. should make it easy to validate the certificate in one single operation (function call)
  2. Return the certificate data (if we can parse that correctly)
  3. Return a clear error in case of validation failed (for instance it's very important to distinguish whether a certificate is expired or whether it doesn't satisfy a specific regional rule)

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...

FYI: Legal use for this parser

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 :-)

Add helpers to easily fetch public keys from the Italian trustlist

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:

We could check the code here or here as a starting point

Rename all "cryptic" fields into more descriptive names

We are currently taking a mixed approach to field naming:

  • All the numeric fields are converted to more descriptive equivalents (e.g. 1 is converted to issuer in DgcCertContainer)
  • Every other fields is not renamed and we end up with things like: 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!

Complete triage using official testing data

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.

Add support for rulesets (business rules) for additional validation of certificates

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!

Implement a method to extract the current test/vaccine/recovery data from a `DgcContainer`

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.

Failing tests with (maybe) wrong data

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.

Support kid in unprotected header

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
    }
}

Refine documentation

Add more examples in the documentation (README) and add proper programmatic documentation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.