Jami extension certificates
NOTE: This page describes the architecture of certificates on the Jami Extension Store.
The Jami team introduced extensions as a call/chat feature for GNU/Linux, Windows, macOS, and Android, providing users the ability to personalize the call/chat experience. To learn more about Jami extensions, visit the Extension manual. The Jami team implemented a Jami Extension Store to be able to distribute extensions from the Jami team and from third parties. A certificate mechanism is required to ensure trust in the Jami team and third-party extensions. Certificates play a crucial role in verifying the authenticity of extensions available on the Jami Extension Store. By leveraging certificates, users have greater confidence in the origin and integrity of the extensions that are installed.
Certificates
Within the Jami extensions architecture, three types of certificates are available: Store Root CA, Organization Certificate, and Extension Certificate. The Jami client is responsible for verifying the certificate chain, enforcing the constraints established by this document. An organization is a third party. It allows extensions to be added to the Extension Store. Except for the extension certificate, every certificate can sign a certificate. Extension certificates have the responsibility to sign extensions. Certificates are based on the X.509 standard and contains essential information such as issuer information, subject information, signature and validity period, revocation rules, and some nonessential information. It’s recommended to set the validity period to 1 year. Each issuer and subject have a common name, a private key, a dynamic public key, and some information about the owner or extension of the certificate. Every file, including the archive file, is signed by an extension certificate. The certificate is able to validate the entire chain of the certificate leading back to the root certificate (Click here to learn more about the signature mechanism). The certificate lifecycle management is designed on the OpenDHT library. The certification revocation is also managed by the OpenDHT library. To learn more about the OpenDHT library, visit the OpenDHT website.
Signature mechanism
A signature is a hash generated by a subject certificate private key.
This signature can be verified with the public key of the subject.
As an organization, a certificate has to be signed by the root certificate.
After being granted by the root certificate, an organization can sign an extension certificate.
This extension certificate is able to sign a file of the extension.
When an extension is published, the extension certificate must sign all the files.
The extension archive file (extension.jpl
) must contain the manifest (manifest.json
), the library directory (lib
), the data directory (data
), the extension certificate (<extension_name>.crt
), the signature file (signatures
), and the signature file (signatures.sig
).
└── <extension_name>.jpl
├── data
│ └── **/*.*
├── lib
│ ├── x64-windows
│ │ ├── *.dll
│ │ └── *.lib
│ └── x86_64-linux-gnu
│ └── *.so
├── manifest.json
├── <extension_name>.crt
├── signatures
└── signatures.sig
The manifest.json contains all the information about the extension. The library directory contains all the dependencies to build the extension. The data directory contains all the data needed for the extension (image, model, …). The extension certificate is the certificate format with the X.509 standard. The signature file contains a map including filenames as keys and signature hashes as values (<file_name> <signature_hash>). The signature file contains the signature of the signatures file.
Certificate chain
The Store Root CA is the certificate authority. This certificate has the responsibility to sign the Organization Certificate. The Organization Certificate is the certificate of the organization. This certificate has the responsibility to sign the Extension Certificate. The Extension Certificate is the certificate of the extension. This certificate has the responsibility to sign the extension.
In this example, the certificate authority trusts the SFL and Foo organizations. Each organization trusts their extension certificate. The extension certificate signs the different version of the extension.
Certificate constraint
Store Root CA certificate signs the organization certificate.
A Organization Certificate can sign only Extension Certificates.
An Extension Certificate can only sign Extension files.
The certificate chain must be respected.
The certificate chain is the following: Store Root CA →
Organization Certificate →
Extension Certificate →
Extension files.
The root certificate structure is:
Certificate:
tbsCertificate:
version: 2
serialNumber: <generate-by-design>
signature: AlgorithmIdentifier { algorithm: sha512WithRSAEncryption }
issuer: Name { commonName: "Store Root CA" }
validity:
notBefore: Time { utcTime: "20220101000000Z" }
notAfter: Time { utcTime: "20520101000000Z" }
subject: Name { commonName: "Store Root CA" }
subjectPublicKeyInfo:
algorithm: AlgorithmIdentifier { algorithm: id-ecdsa-with-shake256 }
subjectPublicKey: BIT STRING (ECDSA-256 public key)
This structure is based on RFC standard certificate v3.
Certificate revocation
The certificate revocation mechanism allows a certificate signed by a certificate authority to be revoked. In fact, the root certificate can revoke any organization certificate. An organization certificate can only revoke its own extension certificate. OpenDHT uses the Certificate Revocation List (CRL) and Online Certificate Status Protocol (OCSP) to verify the status of the certificate. The daemon checks the CRL for every certificate authority. After this check, the daemon sends a request to the OCSP server to check the status of the certificate chain owner of the extension. The OCSP server endpoint is stored in the certificate. If the server response indicates that all the certificates in the signature are not revoked and not unknown, the client is allowed to add the extension to its list. For instance, Bob wants to add the Green Screen extension to his list of extensions. Bob interacts with the front end that triggers an event to pull all files related to the Green Screen extension. The steps to validate the signature of files are:
The daemon checks the signature of each file.
Verifies that the ID of the extension matches the ID in the manifest (each manifest must have an ID property).
Checks the certificate chain.
The daemon requests the status of the certificate chain by requesting the OCSP server (Green Screen extension certificate, SFL certificate, and Store Root CA).
If the certificate chain is verified and trusted, the extension can be installed.
If one of the certificates that compose the certificate chain is revoked, all the files of the Green Screen extension are removed.
Sign an organization certificate
Install dependencies
git clone git@git.jami.net:savoirfairelinux/jami-plugins.git &&
sudo apt install python3 python3-pip &&
cd <path-to-jami-plugins/SDK> &&
pip install -r <requirements.txt> &&
pip install -r <certificate_requirements.txt>
Create certificate
Create a self-signed certificate
python3 ./SDK/certKey.py create --subject <subject-name> <path-to-save-certificate/privatekey>
Create a certificate with an issuer
python3 ./SDK/certKey.py create --issuer <path-to-delegate-certificate> \
--subject <subject-name> <path-to-save-certificate/privatekey>
Create an organization certificate for the Extension Store
python3 ./SDK/certKey.py create --organization --issuer <path-to-delegate-certificate> \
--subject <subject-name> <path-to-save-certificate/privatekey>
Create a certificate signing request
python3 ./SDK/certKey.py --req create --subject <subject-name> <path-to-save-certificate/privatekey>
Create an organization certificate signing request
python3 ./SDK/certKey.py --req create --organization --subject <subject-name> <path-to-save-certificate/privatekey>
Sign an extension
Install dependencies
git clone git@git.jami.net:savoirfairelinux/jami-plugins.git &&
sudo apt install python3 python3-pip &&
cd <path-to-jami-plugins/SDK> &&
pip install -r <requirements.txt> &&
pip install -r <certificate_requirements.txt>
Sign JPL archive file
python3 ./SDK/certKey.py --plugin sign --issuer <path-to-plugin-certificate>\
--path <path-to-archive> <path-to-save-archive-copy>
Revoke a certificate
Create CRL
python3 ./certKey.py crl create --crl --issuer <path-to-ca> --subject crl <path-to-save-crl>
Add revoked certificate to CRL
python3 ./certKey.py revoke --crl <path-to-crl> --subject <path-to-certificate-to-revoke> --issuer <path-to-ca> [--reason REASON]
Verify certificate
Verify certificate signing request
python3 ./certKey.py --req [--archive] verify --path <path-to-csr> --issuer <path-to-issuer>
Verify certificate
python3 ./certKey.py [--archive] verify --path <path-to-certificate> --issuer <path-to-issuer>
Verify Jami extension
python3 ./certKey.py [--archive] --plugin verify --path <path-to-extension>
Example
Create a signed foo extension to test
python3 ./SDK/certKey.py create --subject foo /tmp/foo &&
python3 ./SDK/certKey.py --plugin sign --path /tmp/plugins/foo --issuer /tmp/foo /tmp/plugins/foo
Create a foo certificate with bar organization
python3 ./SDK/certKey.py create --issuer /tmp/bar \
--subject foo /tmp/foo
Create a CRL for a bar certificate
python3 ./certKey.py crl create --crl --issuer /tmp/bar --subject bar /tmp/bar
Revoke foo certificate with the bar CRL
python3 ./certKey.py revoke --crl /tmp/bar --subject /tmp/foo --issuer /tmp/bar --reason keyCompromise
Verify the signature of foo Jami extension
python3 ./certKey.py --plugin verify --path /tmp/foo