DgcReader.TrustListProviders.Abstractions 2.5.5-CI-20230402-101020

This is a prerelease version of DgcReader.TrustListProviders.Abstractions.
There is a newer version of this package available.
See the version list below for details.
dotnet add package DgcReader.TrustListProviders.Abstractions --version 2.5.5-CI-20230402-101020                
NuGet\Install-Package DgcReader.TrustListProviders.Abstractions -Version 2.5.5-CI-20230402-101020                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DgcReader.TrustListProviders.Abstractions" Version="2.5.5-CI-20230402-101020" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DgcReader.TrustListProviders.Abstractions --version 2.5.5-CI-20230402-101020                
#r "nuget: DgcReader.TrustListProviders.Abstractions, 2.5.5-CI-20230402-101020"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DgcReader.TrustListProviders.Abstractions as a Cake Addin
#addin nuget:?package=DgcReader.TrustListProviders.Abstractions&version=2.5.5-CI-20230402-101020&prerelease

// Install DgcReader.TrustListProviders.Abstractions as a Cake Tool
#tool nuget:?package=DgcReader.TrustListProviders.Abstractions&version=2.5.5-CI-20230402-101020&prerelease                

DgcReader

Extensible .NET library for decoding and validating European Digital Green Certificates

NuGet version (DgcReader) Nuget CodeQL

Summary

The library allows to decode and validate any EU Digital Green Certificate, providing some abstractions to easily implement specific providers for every country backend.

It supports any kind of project compatible with .NET Standard 2.0 and also legacy applications from .NET Framework 4.5.2 onwards.

Starting from version 1.3.0, the library has been included in the list of verified SDKs by Italian authorities (Ministero della salute).
The approval only refers to the main module DgcReader in combination with the Italian providers included in the project (DgcReader.RuleValidators.Italy, DgcReader.BlacklistProviders.Italy and DgcReader.TrustListProviders.Italy )
Please refer to this guide in order to correctly configure the required services.

For usage in different countries, please refer to the disclaimer and to the specific documentation of each project.

Usage

The main entry point of the library is the DgcReaderService class.

You can simply register it as a service:

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.AddDgcReader()                     // Add the DgcReaderService as singleton
       .AddItalianTrustListProvider(o =>       // Register at least one trust list provider
       {
           // Optionally, configure the provider with custom options
           o.RefreshInterval = TimeSpan.FromHours(24);
           o.MinRefreshInterval = TimeSpan.FromHours(1);
           o.SaveCertificate = true;
           ...
       })
       .AddItalianDrlBlacklistProvider()      // The blacklist provider(s)
       .AddItalianRulesValidator()         // Finally, the rule validator(s)
       .AddGermanRulesValidator();         // Each rule validator will enable more acceptance countries to be supported
}

then getting it from the DI ServiceCollection:


...
// Getting an instance by dependency injection (from .NET standard 2.0 onward)
var dgcReader = ServiceCollection.GetService<DgcReaderService>();

If you don't use the dependency injection, you can instantiate it directly:

a) Use factory methods:
// Create an instance of the TrustListProvider (eg. ItalianTrustListProvider) and the other required services
var httpClient = new HttpClient();
var trustListProvider = new ItalianTrustListProvider(httpClient);
var drlBlacklistProvider = new ItalianDrlBlacklistProvider(httpClient);
var rulesValidator = new DgcItalianRulesValidator(httpClient);

// Create an instance of the DgcReaderService
var dgcReader = DgcReaderService.Create(
        trustListProviders: new[] { trustListProvider },
        blackListProviders: new IBlacklistProvider[] { rulesValidator, drlBlacklistProvider },
        rulesValidators: new[] { rulesValidator });

Once instantiated and configured with at least the ITrustListProvider service, you can simply call one of the methods shown in c)

b) Use the DgcReaderService for decoding only (no validation):

This lets you decode all the QR code data without verification, but still gives you a quick idea about how the library works. You can use the open source EU Digital Green Test Certificates or your personal certificate.

// Create the default instance of the `DgcReaderService` with an empty constructor
var dgcReader = new DgcReaderService();
var decoded = await dgcReader.Decode("HC1:01234...");
c) Run the validation
...
string qrCodeData = "Raw qr code data staring with HC1:";
string acceptanceCountry = "IT";    // Specify the 2-letter ISO code of the acceptance country

// Decode and validate the qr code data.
// The result will contain all the details of the validated object
var result = await dgcReader.GetValidationResult(qrCodeData, acceptanceCountry);

var status = result.Status;
// Note: all the validation details are available in the result
...

or

...
string qrCodeData = "Raw qr code data staring with HC1:";
string acceptanceCountry = "IT";    // Specify the 2-letter ISO code of the acceptance country
try
{
    // Decode and validate the signature.
    // If anything fails, an exception is thrown containing the error details
    var result = await dgcReader.Verify(qrCodeData, acceptanceCountry);
}
catch(Exception e)
{
    Console.WriteLine($"Error verifying DGC: {e.Message}");
}

Information about how to interprete the decoded values can be found in the Value Sets for Digital Green Certificates and the COVID-19 Data Reporting for Non-Lab-Based Testing.

What's new in 2.0

The new version of the service supports validation for multiple acceptance countries by registering multiple validator services.
It support also registration of multiple TrustList providers and BlackList providers.

In order to support these new features, there are some breaking changes that must be taken into account when upgrading from version 1.x:

  • The DgcReaderService constructor now accepts multiple instances for each kind of service.
    If you don't need to add multiple providers per kind and you don't use dependency injection, you can simply use the Create factory method.
  • Methods Verify and GetValidationResult now requires to specify the acceptance country
  • Files stored by the providers are now organized in subfolders relative to the BasePath option
  • The DgcValidationResult and the exceptions has been reorganized in a cleaner way, and the DgcResultStatus values are less bound to countries specific rules.
    If you need, you can still access specific informations or customized status for a specific implementation of a RuleValidator service by accessing the RulesValidation property of the result.
    By checking the actual implementation, you will get all the details returned by the RuleProvider used for the validation:
...
if (result.RulesValidation is ItalianRulesValidationResult italianResult)
{
    var italianStatus = italianResult.ItalianStatus;    // Access specific status, according to the official Italian SDK
}
else if (result.RulesValidation is GermanRulesValidationResult germanResult)
{
    // do something else...
}

In order to simplify this operation, each RuleValidator may expose some extension methods:

...

var result = await dgcReader.Verify(data, "AT"); // Get validation result for country "AT"

var germanRulesResult = result.GetGermanValidationResult();          // This should return the RulesValidation property as GermanRulesValidationResult, because the german validator supports Austria as an acceptance country
var italianRulesResult = result.GetItalianValidationResult();   // This will return null

Please refer to each RuleValidator readme for more details.

Understanding validation workflow with multiple providers

There are some differences about how each service type is managed by the validation workflow.
When registering multiple services, the following logic is applied:

  • Multiple 'IRulesValidator': having multiple rule validators increases the capability of the service, by expanding the list of supported acceptance countries. When validating a certificate, a validator supporting the required country will be searched.

    • If no validators are found, the validation fails with status NeedRulesVerification
    • If the validator could not return a final verdict (NeedRulesVerification or OpenResult), the service will try to validate the certificate with the next available validator for the acceptance country, if any.
    • When a validator can obtain a final result, either positive or negative, the result is returned.
    • Otherwise, if a final result is not available, the result obtained from the last validator is returned.
  • Multiple 'IBlackListProvider': the certificate identifier will be searched in every registered provider, unless a match is found. The first match will cause the Blacklist check to fail. Using multiple blacklist providers increases the propability of a match for a banned certificate.

  • Multiple ITrustListProvider: when checking for signature validity, the public key of the certificate is searched using each provider, until a match is found. The first match found will be used for validating the signature, without searching it in the remaining TrustList providers. Registering multiple trustlist providers can improve resiliency to national service backend temporary issues, or delays in propagation of the trusted certificates.

Supported frameworks differences

The library supports a wide range of .NET and .NET Framework versions, trying to keep the dependencies to third party libraries at minimum. For this reason, the implementation of the cryptographic functionalities for signature validations and certificates parsing are implemented with the apis of the System.Security.Cryptography namespace.
These APIs were not fully implemented in previous versions of the framework, so the version compiled for .NET Framework 4.5.2 uses the BouncyCastle library instead.

Packages

Description Version
Main package, containing the DgcReaderService NuGet version (DgcReader) Nuget
TrustList implementation for the Italian backend NuGet version (DgcReader.TrustListProviders.Italy) Nuget
TrustList implementation for the Swedish backend NuGet version (DgcReader.TrustListProviders.Sweden) Nuget
TrustList implementation for the German backend NuGet version (DgcReader.TrustListProviders.Germany) Nuget
Implementation of the Italian Blacklist provider NuGet version (DgcReader.BlacklistProviders.Italy) Nuget
Implementation of the Italian validation rules NuGet version (DgcReader.RuleValidators.Italy) Nuget
Implementation of the German rules validation engine NuGet version (DgcReader.RuleValidators.Germany) Nuget
Abstractions for building providers and rules validators NuGet version (DgcReader.Providers.Abstractions) Nuget
Abstractions for building TrustList providers NuGet version (DgcReader.TrustListProviders.Abstractions) Nuget

Extending the library

All you have to do in order to extend the library is to implement the interfaces exposed under the DgcReader.Interfaces.* namespace. You can use the implementations in the repository as an example, or you can code them from scratch.
If you are implementing a TrustList provider, the DgcReader.TrustListProviders.Abstractions package can results useful to simply implement a service optimized for multiple concurrent requests like a web application.
Any suggestion will be appreciated!

Requirements

In order to compile and run the solution, you will need the following tools:

  • Microsoft Visual Studio 2019 with the latest updates installed (16.11.7 at the moment of writing), or Microsoft Visual Studio 2022
  • Because some projects supports multiple version of the .NET framework, you should have installed the related targeting packs. At the moment, .NET Framework 4.5.2, .NET Framework 4.7 and .NET Standard 2.0 are supported

<a name="disclaimer">Disclaimer</a>

Some implementations in this repository may not have been approved by official authorities, or may be approved only by some countries.
Unless otherwise indicated, such implementations must be considered unofficial, and it is not assured in any way that they fully comply with dispositions of the reference countries.

The author assumes no responsibility for any unauthorized use of the library and no warranties about the correctness of the implementation, as better stated in the License.

Some code of the library is based on the DCCValidator App.
Many thanks to their authors for sharing their code!


Copyright © 2021 Davide Trevisan
Licensed under the Apache License, Version 2.0

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net452 is compatible.  net46 was computed.  net461 was computed.  net462 was computed.  net463 was computed.  net47 is compatible.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on DgcReader.TrustListProviders.Abstractions:

Package Downloads
DgcReader.TrustListProviders.Italy

Trustlist provider implementation using certificates from the official Italian backend. This provider is included in the list of verified SDKs by Italian authorities

DgcReader.TrustListProviders.Sweden

Unofficial TrustList provider implementation using the Swedish backend endpoints

DgcReader.TrustListProviders.Germany

Unofficial TrustList provider implementation using the German backend endpoints

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.6.1 875 4/3/2023
2.6.0 880 4/2/2023
2.6.0-CI-20230402-140522 621 4/2/2023
2.5.5 1,702 6/14/2022
2.5.5-rc1 704 6/14/2022
2.5.5-CI-20230402-112357 602 4/2/2023
2.5.5-CI-20230402-101020 590 4/2/2023
2.5.4 1,586 5/4/2022
2.5.4-rc2 644 5/4/2022
2.5.4-rc1 631 5/4/2022
2.5.3 2,272 3/5/2022
2.5.3-rc1 692 3/5/2022
2.5.1 1,632 2/16/2022
2.5.1-rc1 663 2/15/2022
2.5.0 1,636 2/14/2022
2.5.0-rc3 653 2/14/2022
2.5.0-rc2 693 2/11/2022
2.5.0-rc1 645 2/11/2022
2.4.0 1,581 2/6/2022
2.3.0 1,649 1/28/2022
2.2.1 1,658 1/21/2022
2.2.0 1,164 1/16/2022
2.1.0 1,020 1/6/2022
2.0.0 982 12/27/2021
1.3.0 1,085 12/6/2021
1.2.0 997 11/4/2021
1.0.0 971 11/2/2021
1.0.0-CI-20211102-130745 708 11/2/2021
1.0.0-CI-20211102-124304 682 11/2/2021
1.0.0-CI-20211102-120059 719 11/2/2021