Aller au contenu

Signer

Ce contenu n’est pas encore disponible dans votre langue.

Status: Draft

Introduction

The signer is a component of the EVC software suite that enables the signing and generation of the EVC in a portable format.

This software is developed using the Ruby language and the following libraries:

  • base45
  • openssl
  • cbor
  • falcon
  • rqrcode
  • jwt
  • rack

Each of these libraries is used to perform specific tasks, such as encoding and decoding data, signing data, and generating QR codes.

The signer exposes an API that allows for signing the EVC and generating QR codes. It is designed as a toolbox accessible through a JSON-RPC server that provides access to several procedures:

  • sign
  • generate QR code (SVG, PNG)
  • zip data
  • encode data in base45
  • verify the signature
  • etc.

These procedures allow anyone to use the signer to sign and generate a portable version of the EVC in any language with a default implementation. This approach allows you to use the default implementation or to customize certain parts. For example, you can use the signer to sign the EVC, return it as a base45 string, and generate the QR code on your side.

APIs

The signer exposes two APIs:

  • A JSON-RPC API
  • A standard API to retrieve the public key

JSON-RPC API

All procedures are exposed through the same endpoint: POST on /jsonrpc. The body of the request must be a JSON-RPC request.

Here is a list of the available procedures:

  • to_base_45: Encode data in base45
  • to_cwt: Generate an HCERT CWT
  • to_jwt: Generate an HCERT JWT
  • to_zip: Zip data
  • to_hcert: Generate an HCERT (compressed CWT in base45)
  • to_hcert_qr_code: Compressed CWT in base45 as a QR code
  • to_jwt_qr_code: Compressed JWT in base45 as a QR code
  • pipeline: A procedure that allows chaining several procedures
  • from_hcert: Decode an HCERT and verify the signature

Public Key API

The public key is exposed at the /.well-known/jwks.json endpoint. It uses the JWKS format to expose the public key.

Running the Signer

The simplest way to run the signer is to use the Docker image.

Terminal window
docker build -t signer .
docker run -p 3000:3000 signer

By default, the signer will listen on port 3000. It boots using the config.ru file and uses an example key pair to sign the EVC.

Generating your own Docker image

In order to deploy the signer in your own environment, you have to build your own Docker image from this one. The signer uses a basic interface for key pair storage that allows you to implement your own key store. The config.ru file must be overwritten with a version containing your own key pair.

config.ru to adapt:

# frozen_string_literal: true
require 'jwt'
require 'rack/cors'
require 'rack/deflater'
require_relative './initializers'
nuva = ''
Initializers.init_all(nuva:) => { app:, jwks_server:, pub_key_store:, priv_key_store: }
use Rack::CommonLogger
use Rack::Deflater
use Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: %i[get post]
end
end
full_app =
Rack::Builder.app do
map '/jsonrpc' do
run app
end
map '/.well-known/jwks.json' do
run jwks_server
end
map '/healthz' do
run ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['OK']] }
end
end
# A.2.3. Elliptic Curve Digital Signature Algorithm (ECDSA) P-256 256-Bit
# https://datatracker.ietf.org/doc/html/rfc8392#appendix-A.2.3
pub_key_store.add(
JWT::JWK.new(
{
kty: 'EC',
crv: 'P-256',
x: 'FDMpzOeGjkFpJ1mc9lo0884v/aVafspp7YkZo5TULw8',
y: 'YPfxp4DYp4O/t6LdayeW6BKNu87509Fo25Uplxo257k',
kid: 'AsymmetricECDSA256'
}
)
)
priv_key_store.add(
JWT::JWK.new(
{
kty: 'EC',
crv: 'P-256',
alg: 'ES256', # required for JWT.encode
x: 'FDMpzOeGjkFpJ1mc9lo0884v/aVafspp7YkZo5TULw8',
y: 'YPfxp4DYp4O/t6LdayeW6BKNu87509Fo25Uplxo257k',
d: 'bBOCdlrsU1jxF3M9KBwce9w5iE0EpFoebGfIWLwgbBk',
kid: 'AsymmetricECDSA256'
}
)
)
# RubyVM::YJIT.enable
run full_app

Dockerfile used to build the Docker image:

FROM syadem/signer
WORKDIR /app
COPY config.ru config.ru

Then you can push the generated Docker image to the registry of your choice and deploy it within your infrastructure.

Usage Examples

All examples are based on the JSON-RPC API. To reproduce these examples, you’ll need the curl and jq command-line tools.

Sign and Generate a QR Code (PNG)

In this example, we call the to_hcert_qr_code procedure.

First, create a file named to_hcert_qr_code_png.json with the following content:

{
"jsonrpc": "2.0",
"id": "1234",
"method": "to_hcert_qr_code",
"params": {
"file_format": "png",
"hcert_data": {
"ver": "1.0.0",
"nam": {
"fnt": "Jean",
"gnt": "Michel"
},
"dob": "1978-01-01",
"v": []
}
}
}

Then, run the following command:

Terminal window
curl -X POST localhost:3000/jsonrpc -d @./to_hcert_qr_code_png.json | jq -r .result | base64 -D > test.png

You should now have a test.png file in your current directory.

Some explanations:

  • All procedures are called with a POST request to the /jsonrpc endpoint.
  • The procedure name is specified in the method field of the request body.
  • The parameters are provided in the params field of the request body.
  • The result is in the result field of the response (jq -r .result).
  • All binary results are base64 encoded, so we use base64 -D to decode them.