Description

J’ai dû récemment rechercher une solution permettant de signer numériquement un document PDF. Pensant que je ne suis pas le seul à avoir ce genre de problématique, je mets à la disposition du public le résultat de mes tests.

Cela permet de générer automatiquement ce genre d’image dans le document PDF, surtout de le signer numériquement et donc d’interdire toute modification en précisant de façon certaine « l’émetteur » (le signataire du document). Il apparait sur cette image le texte Validité inconnue la cause de cela est l’utilisation d’un « certificat auto-signé » pour signer ce PDF.

Ou « Signature Valable » si vous utilisez un certificat avec une autorité racine valide (Verisign, ..)

Outils utilisés

  • Acrobat reader 7.x ou sup Pour visualiser le document généré
  • iText 2.x Pour générer et signer le document
  • bouncycastle.org pour itext (bcprov)
  • Un certificat PKCS12 (acheté ou généré) attention si vous générez vous même votre clef il n’est pas possible de valider la chaine des certificat (ce qui est normal)

Exemple (code source)

Comme vous pouvez le voir le code java pour réaliser cela est très simple il est divisé en deux parties :

  • la méthode buildPDF : qui permet de construire un document PDF , (c’est une option)
  • la méthode signPdf : qui signe le document PDF
package com.berthou.test.pdf ;
 
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
 
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
 
public class sign_pdf  {
 
	/**
	 * Nom du document PDF généré non signé
	 */
	static String fname  = "D:\\HelloWorld.pdf" ;
 
	/**
	 * Nom du document PDF généré signé
	 */
	static String fnameS = "D:\\HelloWorld_sign.pdf" ;
 
	public static void main(String[] args) {
		try {
			sign_pdf.buildPDF() ;
			sign_pdf.signPdf() ;
		}
		catch(Exception e) { }
	}
 
	/**
	 * Création d'un simple document PDF "Hello World"
	 */
	public static void buildPDF() {
 
		// Creation du document
		Document document = new Document();
 
		try {
			// Creation du "writer" vers le doc
			// directement vers un fichier
			PdfWriter.getInstance(document,
					new FileOutputStream(fname));
			// Ouverture du document
			document.open();
 
			// Ecriture des datas
			document.add(new Paragraph("Hello World"));
 
		} catch (DocumentException de) {
			System.err.println(de.getMessage());
		} catch (IOException ioe) {
			System.err.println(ioe.getMessage());
		}
 
		// Fermeture du document
		document.close();
 
	}
	/**
	 * Signature du document
	 */
	public static final boolean signPdf()
			throws IOException, DocumentException, Exception
	{
		// Vous devez preciser ici le chemin d'acces a votre clef pkcs12
		String fileKey          = "C:\\MonRep\\MaClef.p12" ;
		// et ici sa "passPhrase"
		String fileKeyPassword  = "MonPassword" ;
 
		try {
			// Creation d'un KeyStore
			KeyStore ks = KeyStore.getInstance("pkcs12");
			// Chargement du certificat p12 dans el magasin
			ks.load(new FileInputStream(fileKey), fileKeyPassword.toCharArray());
			String alias = (String)ks.aliases().nextElement();
			// Recupération de la clef privée
			PrivateKey key = (PrivateKey)ks.getKey(alias, fileKeyPassword.toCharArray());
			// et de la chaine de certificats
			Certificate[] chain = ks.getCertificateChain(alias);
 
			// Lecture du document source
			PdfReader pdfReader = new PdfReader((new File(fname)).getAbsolutePath());
			File outputFile = new File(fnameS);
			// Creation du tampon de signature
			PdfStamper pdfStamper;
			pdfStamper = PdfStamper.createSignature(pdfReader, null, '\0', outputFile);
			PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance();
			sap.setCrypto(key, chain, null, PdfSignatureAppearance.SELF_SIGNED);
			sap.setReason("Test SignPDF berthou.mc");
			sap.setLocation("");
			// Position du tampon sur la page (ici en bas a gauche page 1)
			sap.setVisibleSignature(new Rectangle(10, 10, 50, 30), 1, "sign_rbl");
 
			pdfStamper.setFormFlattening(true);
			pdfStamper.close();
 
			return true;
		}
		catch (Exception key) {
			throw new Exception(key);
		}
	}
}

Exemple de document généré

HelloWorld_sign.pdf

Un complément à cette article est proposé dans MS CAPI et Java (JCE SunMSCAPI).

Be Sociable, Share!