ec.rubrica.pdf.FirmaPDF.java Source code

Java tutorial

Introduction

Here is the source code for ec.rubrica.pdf.FirmaPDF.java

Source

/*
 * Copyright (c) 2009-2013 Rubrica.ec
 * 
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 */

package ec.rubrica.pdf;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.logging.Logger;

import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.bouncycastle.tsp.TimeStampToken;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.CertificateInfo;
import com.itextpdf.text.pdf.security.CertificateVerification;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.KeyStoreUtil;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.TSAClient;

import ec.rubrica.cert.securitydata.SecurityDataSubCaCert;

/**
 * Clase para firmar documentos PDF usando la libreria iText.
 * 
 * @author Ricardo Arguello <ricardo@rubrica.ec>
 */
public class FirmaPDF {

    private static final Logger logger = Logger.getLogger(FirmaPDF.class.getName());

    public static byte[] firmar(byte[] pdf, PrivateKey pk, Certificate[] chain, TSAClient tsaClient)
            throws IOException {
        try {
            // Creating the reader and the stamper
            PdfReader reader = new PdfReader(pdf);
            ByteArrayOutputStream signedPdf = new ByteArrayOutputStream();
            PdfStamper stamper = PdfStamper.createSignature(reader, signedPdf, '\0');

            // Creating the appearance
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setReason("Testing");
            appearance.setLocation("Quito");
            appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");

            // Creating the signature
            PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA1, null);

            OcspClient ocsp = new OcspClientBouncyCastle();

            MakeSignature.signDetached(appearance, pks, chain, null, ocsp, tsaClient,
                    BouncyCastleProvider.PROVIDER_NAME, 0, MakeSignature.CMS);

            return signedPdf.toByteArray();
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * TODO: Mas de dos firmas?
     * 
     * @param pdf
     * @throws IOException
     * @throws SignatureException
     */
    public static boolean verificar(byte[] pdf) throws IOException, SignatureException {

        PdfReader reader = new PdfReader(pdf);
        AcroFields af = reader.getAcroFields();
        ArrayList<String> names = af.getSignatureNames();

        for (int k = 0; k < names.size(); ++k) {
            String name = (String) names.get(k);
            System.out.println("Signature name: " + name);
            System.out.println("Signature covers whole document: " + af.signatureCoversWholeDocument(name));
            System.out.println("Document revision: " + af.getRevision(name) + " of " + af.getTotalRevisions());

            PdfPKCS7 pk = af.verifySignature(name);
            Calendar cal = pk.getSignDate();
            Certificate[] pkc = pk.getCertificates();
            TimeStampToken ts = pk.getTimeStampToken();

            if (ts != null) {
                cal = pk.getTimeStampDate();
            }

            if (!pk.isTsp() && ts != null) {
                boolean impr;
                try {
                    impr = pk.verifyTimestampImprint();
                    System.out.println("Timestamp imprint verifies: " + impr);
                    System.out.println("Timestamp date: " + cal);
                } catch (NoSuchAlgorithmException e) {
                    throw new SignatureException(e);
                }
            }

            System.out.println("Subject: " + CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
            System.out.println("Document modified: " + !pk.verify());

            KeyStore kall = KeyStoreUtil.loadCacertsKeyStore();

            Object fails[] = CertificateVerification.verifyCertificates(pkc, kall, null, cal);

            if (fails == null) {
                System.out.println("Certificates verified against the KeyStore");
            } else {
                System.out.println("Certificate failed: " + fails[0]);
                return false;
            }

            BasicOCSPResp ocsp = pk.getOcsp();

            if (ocsp != null) {
                try {
                    X509Certificate cert = new SecurityDataSubCaCert();

                    boolean verifies = ocsp.isSignatureValid(new JcaContentVerifierProviderBuilder()
                            .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(cert.getPublicKey()));

                    System.out.println("OCSP signature verifies: " + verifies);

                    System.out.println("OCSP revocation refers to this certificate: " + pk.isRevocationValid());

                    return verifies;
                } catch (OperatorCreationException e) {
                    throw new SignatureException(e);
                } catch (OCSPException e) {
                    throw new SignatureException(e);
                }
            } else {
                return true;
            }
        }

        return false;
    }
}