Enveloppe de document
MilleGrilles établi une structure d’enveloppe sécurisée par un hachage et une signature cryptographique pour ses documents.
Les messages sont un type de document particulier qui peuvent transiter sur le bus MQ d’une MilleGrille.
Les autres types de document sont le document de base (kind:0) et la transaction (kind:3 et kind:7). Ces documents ne sont pas faits pour transiter directement sur le bus mais peuvent être inclus dans un message, conservés sur disque ou dans une base de données.
Messages MilleGrilles
Le bus MQ (RabbitMQ) permet d’échanger des messages entre les composants d’une MilleGrille. Ce bus est sécurisé et génère les permissions de chaque client en fonction de son certificat système.
Note : Les certificats usagers ne sont pas autorisés à se connecter au bus de la MilleGrille.
L’enveloppe des messages et autres documents signés (documents, transactions) utilise une structure est inspirée par Nostr .
La taille maximale d’une enveloppe de message sur le bus MQ est 10 méga-octets.
Exemple d’enveloppe de message
{
"id": "b9fead6eef87d8400cbc1a5621600b360438affb9760a6a043cc0bddea21dab6",
"pubkey": "6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93",
"estampille": 1681650062,
"kind": 4,
"routage": {"action": "fichePublique", "domaine": "CoreTopologie", "partition": "ZABC1"},
"origine": "zeYncRqEqZ6eTEmUZ8whJFuHG796eSvCTWE4M432izXrp22bAtwGm7Jf",
"dechiffrage": {
"cles": {"6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93": "jSNQFfzeHPq3DoFaj8YMkCdnd4GzCc2qZDUdywFZlDQ"},
"cle_id": "z4KD61h3yH7jyJBmYYytzCj3Ni6DDW7iSDkuBw9wSUFRo",
"format": "mgs4",
"nonce": "EjQ8MmAx5VY12vtJ3ag8rA9j8DMjzuiS"
},
"pre-migration": {
"estampille": 1671554193,
"id": "5d0ef4c0-94de-4141-8954-7f006cbbbcfd",
"pubkey": "10319064594e3990f78a35b288c83b33029ebab0e14206ea92908985022905a9"
},
"contenu": "{\"Champ\":\"valeur\"}",
"sig": "908a15e46fb4d8675bab026fc230a0e3542bfade63da02d542fb78b2a8513fcd0092619a2c8c1221e581946e0191f2af505dfdf8657a414dbca329186f009262",
"certificat": [
"-----BEGIN CERTIFICATE-----\nMIIClDCCAkagAwIBAgIUdkc2yl6WSpl ... +GFuCp92IBw==\n-----END CERTIFICATE-----\n",
"-----BEGIN CERTIFICATE-----\nMIIBozCCAVWgAwIBAgIKBBdSWFdJiDN ... A6bAfGc7dGHsL\n-----END CERTIFICATE-----\n"
],
"millegrille": "-----BEGIN CERTIFICATE-----\nMIIBQzCB9qADAgECAgo ... H94CH4d1VCPwI\n-----END CERTIFICATE-----",
"attachements": {
"cles": {
"pubkey cert destinataire 1": "cle dechiffrage",
"pubkey cert destinataire 2": "cle dechiffrage"
}
}
}
Cet exemple inclus tous les champs possibles pour un message. Le type de message (kind) détermine quelle combinaison d’éléments sont supportés.
Champs d’une enveloppe de document
- id : Hachage blake2s en format hexadécimal des éléments du message. Le kind détermine les champs et l’ordre utilisé pour ce hachage.
- pubkey : Clé publique ed25519 en format hexadécimal utilisée pour signer le message. Les certificats d’une MilleGrille sont indexés par leur clé publique (hex) pour être facilement retrouvé.
- estampille : Temps epoch en secondes (int) qui représente le moment de création du document/message.
- kind : Type de message. Détermine les éléments requis/optionnels, format de séralisation du contenu et leur ordre d’inclusion dans le hachage (id).
- contenu : Contenu sérialisé en chaine de caractères (string). La méthode de sérialisation du contenu dếpend du kind.
- sig : Signature électronique du id avec la clé ed25519 privée qui correspond à pubkey.
- certificat : Optionnel mais recommandé - la chaîne de certificats X.509 qui correspond à pubkey. Exclus le certificat CA (millegrille).
- millegrille : Optionnel - le certificat CA (millegrille).
- attachements : Optionnel - objet avec un format qui dépend du contexte. Toujours exclus de la signature du document/message.
- origine : Identificateur de MilleGrille (IDMG) de l’origine du message.
- dechiffrage : Information requise pour le déchiffrage du contenu. Peut inclure les clés indexées par pubkey ou un cle_id.
Calcul du hachage
Le hachage du message est généré en mettant les éléments appopriés dans une liste JSON et calculant le hachage blake2s de cette chaîne de caractères.
Hachage par kind
| Kind | Description | Hachage | Format contenu |
|---|---|---|---|
| 0 | Document | pubkey, estampille, kind, contenu | json string |
| 1 | Requête | pubkey, estampille, kind, routage, contenu | json string |
| 2 | Commande | pubkey, estampille, kind, routage, contenu | json string |
| 3 | Transaction | pubkey, estampille, kind, routage, contenu | json string |
| 4 | Réponse | pubkey, estampille, kind, contenu | json string |
| 5 | Événement | pubkey, estampille, kind, routage, contenu | json string |
| 6 | Réponse chiffrée | pubkey, estampille, kind, déchiffrage, contenu | base64 nopad (json string -> mgs4) |
| 7 | Transaction migrée | pubkey, estampille, kind, routage, contenu | json string |
| 8 | Commande inter-millegrille | pubkey, estampille, kind, routage, origine, déchiffrage, contenu | base64 nopad (json string -> mgs4) |
Par exemple, pour le kind:4 - Réponse, le hachage est calculé de la façon suivante:
[pubkey,estampille,kind,contenu]
Pour le message en exemple, on aurait :
["6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93",1681650062,4,"{\"Champ\":\"valeur\"}"]
Le message JSON précédent est converti en UTF-8 puis haché avec blake2s. Ceci donne une valeur de 32 bytes (64 caractères hexadécimaux). Cette valeur devient le id du message.
Note : Pour les champs objet (routage, dechiffrage et pre-migration), il faut s’assurer de trier les sous-éléments en ordre alphabétique pour obtenir la bonne valeur de hachage. Les éléments dans l’exemple sont dans le bon ordre.
Signature électronique
Le champ sig contient une signature électronique du champ id.
La signature est générée en utilisant la clé privée ed25519 qui correspond à pubkey et la valeur binaire de id comme contenu.
La signature peut être vérifiée en utilisant le champ pubkey (hex) comme clé ed25519 et la valeur binaire de id comme contenu.
Vérification d’un document
Pour vérifier la validité d’un message, il faut recalculer le id pour s’assurer qu’il correspond puis valider la signature en utilisant le hachage puis pubkey.
Une fois le message validé, il est généralement utile de charger le certificat correspondant à pubkey pour extraire l’information d’autorisation comme le userId, instance, les domaines, etc. Ces valeurs doivent être privilégiées par rapport au contenu du message pour autoriser une requête ou une commande lorsque c’est possible. Lorsque ce n’est pas possible, les domaines, userId peuvent être placés dans le contenu du message - par exemple pour permettre à un administrateur d’exécuter une commande au nom d’un usager.
Note : si le certificat est inclus dans le document, s’assurer qu’il est valide (validation X.509) que sa clé publique correspond au champ pubkey du document.
Chiffrage du contenu
Documents avec contenu chiffré
Les documents peuvent contenir un ou plusieurs des éléments chiffrés.
Exemple
{
tuuid: 'a4a3397e8002c5beabcd03e25f46c4334c8eeceee49b02d3528c1a4b758a888d',
user_id: 'z2i3XjxLmXHZZyfWszu4Kui7Nv6dKWaujpYTcJ9dSHZJCJ5sTm6',
type_node: 'Fichier',
'_mg-derniere-modification': ISODate('2025-03-16T17:04:30.571Z'),
'_mg-creation': ISODate('2025-02-24T23:55:46.652Z'),
flag_index: true,
supprime: false,
supprime_indirect: false,
metadata: {
data_chiffre: 'vjp8jo04zC4lTGfevDm91y8LsqNw31lze1A8f7+Qesyel4/5jMqOOLAbZZKnzM83GoJfre4XlEq3yPl0KXOMGHanAxtNmiQM9ehFXAUsdxXxpLR2WD6FR/iAndJH5nssp5Sghsqtu2TkoUa3FJboMV7lw2CPzg6p4ezP5WMRBFd3oMITl09WRY+IjtWogLczyorbvKB8frjUkRpc0Ym1obH9dpY9pg==',
cle_id: 'z59EzgDUKK68RVT1MpBH3eF6VD9cJkMgV3aznaKaGrp2W',
format: 'mgs4',
nonce: 'Ej72ZPe5FYamAjPvVObkdr6PMAmoGuJ3'
},
mimetype: 'image/png',
fuuids_versions: [
'zSEfXUDjM1yQz23RnFiCmdN2RgjNHBTV1DC2R6LFj8qwFJbtZiEhXKc1AnsW7NiptSVzpK59pnyqsmyDCzsLGsBdw7R5mn'
],
path_cuuids: [
'8bd9d3c477a818b42292cc39003e18ac9861d38c7b3811384acfb4983178f83e',
'b6ba87ecb3b96fbe8ce173457648517346119fcad1a3f555d724948e4223254e'
]
}
Chiffrage des réponses
Le chiffrage des réponses est supporté directement et de manière transparente. Le certificat de la requête/commande qui est utilisé pour chiffrer la réponse (kind:6). Le module qui reçoit la réponse déchiffre de manière transparente le contenu pour simuler une réponse de kind:4.
La réponse chiffrée est utile pour garantir la sécurité end-to-end d’un contenu sensible qui peut inclure des clés de déchiffrage ou de l’information qui ne doit pas être interceptée (numéros de cartes de crédit/bancaire). Ces messages ne peuvent pas être ouverts par les composants intermédiaires qui assurent le transit entre la base de données et le composant requérant (e.g. navigateur de l’usager).
Chiffrage des requêtes ou commandes
Format json serializé en texte
Le champ contenu utilise un message json serializé en text UTF-8. Le choix de ce format est pour garantir l’intégrité du message lors de la vérification.
La première version de message pour MilleGrilles (2019-2022) utilisait un format pur JSON pour les valeurs. L’utilisation de certains parsers en C et Rust ont montré une approche différente entre le traitement des floats 32-64 bits comparé à Python 3 et JavaScript. Cette différence causait des erreurs de vérifications inopinées et purement dues à la dé-sérialisation à la réception puis re-sérialisation du même message pour la vérification.
L’utilisation du format texte a réglé ces problèmes puisqu’il n’y a aucune interprétation requise durant la désérialisation de l’enveloppe d’un type de document MilleGrille (aucunes valeurs float).