Mayan EDMS propose deux systèmes de signature totalement indépendants :
| Système | App | Nature | Vérifiable ? | Lié à |
|---|---|---|---|---|
| Signature GPG | document_signatures |
Cryptographique (non-répudiation) | Oui, mathématiquement | DocumentFile |
| Capture manuscrite | signature_captures |
Visuelle (tracé/SVG) | Non (confiance implicite) | Document |
Ce guide couvre principalement les signatures GPG, qui sont la forme d'authentification forte. Les captures manuscrites sont décrites en fin de document.
Une signature GPG prouve deux choses :
Mayan utilise une infrastructure à clé publique (PKI) standard GPG/PGP :
Signataire Vérificateur
────────── ────────────
Clé privée (secrète) → signe
Clé publique (partagée) → vérifie
DetachedSignature)Le fichier de signature (.sig ou .asc) est séparé du document original. Le document lui-même n'est pas modifié.
document.pdf ← document original inchangé
document.pdf.sig ← fichier de signature séparé (stocké dans Mayan)
Avantages : le document original est préservé à l'identique, la signature peut être supprimée sans toucher au document, plusieurs signatures détachées peuvent coexister sur le même fichier.
EmbeddedSignature)La signature est intégrée dans le fichier lui-même. Le résultat est un nouveau fichier GPG signé, qui remplace le fichier précédent comme nouvelle version.
document.pdf.gpg ← document + signature dans le même fichier
Avantages : tout-en-un, impossible de séparer document et signature, format standard GPG reconnu hors de Mayan.
Avant de pouvoir signer ou vérifier des documents, les clés GPG doivent être importées dans Mayan.
| Action | Permission requise |
|---|---|
| Voir la liste des clés | permission_key_view |
| Importer une clé (upload) | permission_key_upload |
| Supprimer une clé | permission_key_delete |
| Télécharger une clé | permission_key_download |
| Importer depuis un keyserver | permission_key_receive |
| Utiliser une clé pour signer | permission_key_sign |
| Rechercher sur un keyserver | permission_keyserver_query |
La clé publique du signataire doit être dans le trousseau Mayan pour que la vérification soit possible.
Via l'interface :
Key data-----BEGIN PGP PUBLIC KEY BLOCK-----
... (contenu de la clé) ...
-----END PGP PUBLIC KEY BLOCK-----
Via le keyserver :
Via l'API REST :
POST /api/v4/keys/
Content-Type: application/json
{
"key_data": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n..."
}
La clé privée est nécessaire pour signer des documents. Elle doit contenir à la fois la partie privée et publique.
⚠️ La clé privée est stockée en base de données. Assurez-vous que l'accès à Mayan et sa base de données sont sécurisés.
Procédure : identique à l'import de clé publique — Mayan détecte automatiquement le type (sec = privée, pub = publique).
Vérification : Menu → Clés → Clés privées — la clé doit y apparaître.
En cliquant sur une clé (/keys/<id>/) :
| Champ | Description |
|---|---|
| Key ID | Identifiant court (8 hex) |
| Fingerprint | Empreinte complète (40 hex) |
| Type | Publique / Privée |
| Algorithm | RSA, DSA, etc. |
| Length | Taille en bits (ex : 4096) |
| User ID | Identité ("Alice <alice@example.com>") |
| Creation date | Date de création de la clé |
| Expiration date | Date d'expiration (si définie) |
| Action | Permission requise |
|---|---|
| Signer avec signature détachée | permission_document_file_sign_detached |
| Signer avec signature intégrée | permission_document_file_sign_embedded |
| Utiliser la clé privée | permission_key_sign |
Ces permissions s'appliquent sur le document (via ACL objet ou rôle global).
/signatures/documents/files/<file_id>/signatures/detached/create/permission_key_sign apparaissent)Résultat : un enregistrement DetachedSignature est créé, le fichier .sig est stocké dans Mayan. Le document original n'est pas modifié.
Erreurs possibles :
/signatures/documents/files/<file_id>/signatures/embedded/create/Résultat : un nouveau DocumentFile est créé — c'est le document original enveloppé dans une signature GPG binaire. La nouvelle version apparaît dans l'onglet Fichiers du document. La vieille version reste accessible.
⚠️ La signature intégrée crée une nouvelle version du fichier, pas une modification sur place.
Si la signature a été générée hors de Mayan (ex : gpg --detach-sign document.pdf) :
/signatures/documents/files/<file_id>/signatures/detached/upload/.sig ou .ascMayan tente immédiatement de vérifier la signature avec les clés du trousseau.
Signature détachée :
POST /api/v4/documents/<doc_id>/files/<file_id>/signatures/detached/sign/
Content-Type: application/json
{
"key": 3,
"passphrase": "ma_passphrase"
}
Signature intégrée :
POST /api/v4/documents/<doc_id>/files/<file_id>/signatures/embedded/sign/
Content-Type: application/json
{
"key": 3,
"passphrase": "ma_passphrase"
}
Upload d'un .sig existant :
POST /api/v4/documents/<doc_id>/files/<file_id>/signatures/detached/upload/
Content-Type: multipart/form-data
signature_file=@document.pdf.sig
/signatures/documents/files/<file_id>/signatures/La liste affiche toutes les signatures (détachées et intégrées) avec les colonnes :
| Colonne | Description |
|---|---|
| Date and time | Horodatage de la signature |
| Key ID | ID court de la clé (16 hex si fingerprint disponible) |
| Signature ID | ID unique de la signature (ou None si clé absente du trousseau) |
| Type | Detached ou Embedded |
Signature non vérifiée : Signature ID = None — la clé publique n'est pas dans le trousseau Mayan. La signature est connue mais pas vérifiable.
Signature vérifiée : Signature ID rempli — la clé est présente et la signature a été vérifiée avec succès.
⚠️ Note de sécurité : Mayan n'affiche pas explicitement
valid=True/Falsedans l'interface. La présence d'unSignature IDne garantit pas que la signature est cryptographiquement valide (voir vulnérabilités connues).
Cliquer sur une signature → /signatures/<id>/details/
Informations affichées :
| Champ | Description |
|---|---|
| Signature is embedded? | True / False |
| Signature date | Horodatage GPG de la signature |
| Signature key ID | ID court de la clé |
| Signature key present? | La clé publique est-elle dans le trousseau ? |
| Signature ID | ID unique (si clé présente) |
| Key fingerprint | Empreinte complète |
| Key creation date | Date de création de la clé |
| Key expiration date | Date d'expiration de la clé |
| Key length | Taille en bits |
| Key algorithm | Algorithme (RSA, DSA…) |
| Key user ID | Identité du signataire |
| Key type | Publique / Privée |
Lister les signatures détachées d'un fichier :
GET /api/v4/documents/<doc_id>/files/<file_id>/signatures/detached/
Lister les signatures intégrées d'un fichier :
GET /api/v4/documents/<doc_id>/files/<file_id>/signatures/embedded/
Réponse type :
{
"count": 1,
"results": [{
"date_time": "2024-03-15T14:32:00Z",
"key_id": "ABCDEF1234567890",
"key_algorithm": 1,
"key_creation_date": "2022-01-01T00:00:00Z",
"key_expiration_date": null,
"key_length": 4096,
"key_type": "pub",
"key_user_id": "Alice <alice@example.com>",
"key_url": "/api/v4/keys/3/",
"public_key_fingerprint": "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
"signature_id": "ABCD1234ABCD1234",
"document_file_url": "/api/v4/documents/1/files/5/",
"url": "/api/v4/documents/1/files/5/signatures/detached/2/"
}]
}
signature_id null : clé absente — signature connue mais non vérifiée.
signature_id rempli : signature vérifiée avec la clé publique du trousseau.
Quand un nouveau DocumentFile est créé (upload), Mayan déclenche automatiquement hook_create_embedded_signature via un hook post_save. Ce hook appelle :
EmbeddedSignature.objects.create(document_file=instance)
Cela lance une tentative de vérification GPG immédiate. Si le fichier est un fichier GPG signé, l'EmbeddedSignature est créée et remplie. Sinon, rien n'est créé.
Ce mécanisme est transparent — aucune action utilisateur n'est nécessaire pour détecter les signatures intégrées à l'upload.
Le hook hook_decrypt_document_file (enregistré sur pre_open) est déclenché à chaque ouverture de fichier. Il tente de déchiffrer les documents GPG encryptés-signés via EmbeddedSignature.objects.open_signed(). Ce hook est transparent pour l'utilisateur.
Après l'import d'une nouvelle clé publique, les signatures qui avaient signature_id=null (clé absente) sont automatiquement re-vérifiées par la tâche task_verify_key_signatures.
Cette tâche est déclenchée automatiquement par le signal post_save sur le modèle Key. Aucune action manuelle n'est nécessaire après l'import d'une clé.
Si la re-vérification automatique échoue : utiliser l'outil manuel.
Menu → Outils → section Signatures :
| Outil | URL | Permission | Description |
|---|---|---|---|
| Verify all document for signatures | /tools/all/document/file/signature/verify/ |
signature_verify |
Lance task_verify_missing_embedded_signature — détecte les fichiers GPG signés sans EmbeddedSignature enregistrée |
| Refresh all signatures information | /tools/all/document/file/signature/refresh/ |
signature_verify |
Lance task_refresh_signature_information — re-sauvegarde toutes les signatures pour actualiser leur état |
⚠️ Sur les grandes bases, ces opérations peuvent prendre plusieurs minutes.
Quand une clé GPG est supprimée de Mayan, le signal post_delete déclenche automatiquement task_unverify_key_signatures. Cette tâche re-sauvegarde toutes les signatures associées pour les marquer comme non-vérifiées (signature_id → null).
⚠️ Limitation connue : pour les documents chiffrés avec
EncryptedPassthroughStorage, cette tâche est inopérante (voir section Vulnérabilités).
| Permission | Namespace | Où s'applique | Rôle |
|---|---|---|---|
permission_key_view |
django_gpg |
Global (rôle) | Voir les clés GPG |
permission_key_upload |
django_gpg |
Global (rôle) | Importer une clé |
permission_key_delete |
django_gpg |
Global (rôle) | Supprimer une clé |
permission_key_download |
django_gpg |
Global (rôle) | Exporter une clé |
permission_key_receive |
django_gpg |
Global (rôle) | Import depuis keyserver |
permission_key_sign |
django_gpg |
Global (rôle) | Utiliser la clé pour signer |
permission_keyserver_query |
django_gpg |
Global (rôle) | Recherche keyserver |
permission_document_file_sign_detached |
document_signatures |
Document (ACL objet) | Signer détaché |
permission_document_file_sign_embedded |
document_signatures |
Document (ACL objet) | Signer intégré |
permission_document_file_signature_view |
document_signatures |
Document (ACL objet) | Voir les signatures |
permission_document_file_signature_upload |
document_signatures |
Document (ACL objet) | Uploader un .sig |
permission_document_file_signature_delete |
document_signatures |
Document (ACL objet) | Supprimer une signature |
permission_document_file_signature_download |
document_signatures |
Document (ACL objet) | Télécharger le .sig |
permission_document_file_signature_verify |
document_signatures |
Global (rôle) | Outils de vérification globaux |
Rôle « Signataire » (peut signer des documents) :
permission_key_view
permission_key_sign
permission_document_file_sign_detached (sur ACL document)
permission_document_file_signature_view (sur ACL document)
Rôle « Vérificateur » (peut voir et vérifier les signatures) :
permission_key_view
permission_document_file_signature_view (sur ACL document)
Rôle « Administrateur GPG » (gestion complète des clés) :
permission_key_view
permission_key_upload
permission_key_delete
permission_key_download
permission_key_receive
permission_keyserver_query
permission_document_file_signature_verify
Il est possible de signer automatiquement un document lors d'une transition d'état de workflow.
Dans un workflow, ajouter une action de type « Sign document (detached) » sur une transition.
Configuration :
Exemple : à la transition « Soumis → Approuvé », signer automatiquement le dernier fichier du document avec la clé de l'organisation.
Identique mais produit une signature intégrée. Un nouveau DocumentFile est créé.
⚠️ L'action lève
WorkflowStateActionErrorsi le document n'a pas encore de fichier (état initial avant traitement).
Les captures manuscrites (signature_captures) sont des tracés visuels — elles n'offrent aucune garantie cryptographique. Elles servent à enregistrer une paraphe visuelle dans un workflow de validation humaine.
/documents/<id>/signature_captures/approbation_directionLa capture est rendue en PNG via conversion SVG → CairoSVG → PNG mise en cache.
/signature_captures/<id>/detail/GET /api/v4/documents/<doc_id>/signature_captures/<id>/image/| Permission | Description |
|---|---|
permission_signature_capture_view |
Voir les captures |
permission_signature_capture_create |
Créer une capture |
permission_signature_capture_edit |
Modifier (texte, internal_name) |
permission_signature_capture_delete |
Supprimer |
Signature ID = NoneCause : la clé publique du signataire n'est pas dans le trousseau Mayan.
Solution :
Key ID affiché dans la liste des signaturestask_verify_key_signatures se déclenche automatiquement et remplit signature_idCause possible A : le document n'est pas un fichier GPG signé (signature intégrée non détectée).
Solution : vérifier que le fichier est bien un fichier GPG (file document.pdf.gpg → PGP message). Si c'est un PDF signé au niveau PDF (pas GPG), Mayan ne le détectera pas.
Cause possible B : la tâche Celery task_verify_document_file a échoué.
Solution : Menu → Outils → « Verify all document for signatures »
La clé privée sélectionnée est protégée par une passphrase. Remplir le champ Passphrase dans le formulaire de signature.
La passphrase saisie ne correspond pas à la clé. Vérifier la passphrase de la clé privée.
validMayan n'affiche pas valid=True/False dans l'interface. La présence d'un Signature ID indique que la signature a été vérifiée, mais la branche de code qui remplit ce champ peut s'exécuter même pour des signatures cryptographiquement invalides (VULN 1 — managers.py:147).
Impact utilisateur : une signature forgée pourrait apparaître dans l'interface avec un Signature ID rempli.
Si Mayan utilise EncryptedPassthroughStorage, la suppression d'une clé GPG ne met pas à jour les EmbeddedSignature associées. Les documents restent affichés comme « signés » même après suppression de la clé (VULN 2 — models.py:158-161).
Impact utilisateur : supprimer une clé compromise depuis l'interface ne suffit pas à invalider les signatures — les documents continuent d'afficher Signature ID rempli.
| Vulnérabilité | Fichier | Rapport |
|---|---|---|
| VULN 1 — Signature Bypass | django_gpg/managers.py:133-153 |
security2_report.txt |
| VULN 2 — Silent Failure + raw=True | document_signatures/models.py:155-182 |
security2_report.txt |