de.rub.dez6a3.jpdfsigner.control.ITextSigner.java Source code

Java tutorial

Introduction

Here is the source code for de.rub.dez6a3.jpdfsigner.control.ITextSigner.java

Source

/*
 * JPDFSigner - Sign PDFs online using smartcards (ITextSigner.java)
 * Copyright (C) 2013  Ruhr-Universitaet Bochum - Daniel Moczarski, Haiko te Neues
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/gpl.txt>.
 *
 */

package de.rub.dez6a3.jpdfsigner.control;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.SignatureException;
import java.security.cert.Certificate;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfPKCS7;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignature;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfString;
import com.itextpdf.text.pdf.TSAClient;
import com.itextpdf.text.pdf.TSAClientBouncyCastle;
import de.rub.dez6a3.jpdfsigner.exceptiontypes.PKCS11Exception;
import de.rub.dez6a3.jpdfsigner.control.language.LanguageFactory;
import de.rub.dez6a3.jpdfsigner.model.IDocumentSigner;
import de.rub.dez6a3.jpdfsigner.view.DecoratedJOptionPane;
import java.awt.Rectangle;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.HashMap;
import javax.swing.JOptionPane;
import org.apache.log4j.Logger;

public class ITextSigner implements IDocumentSigner {

    private Configurator config;
    private Provider provider = null;
    private ArrayList<Certificate> signCert;
    private Key signPrivKey = null;
    private char[] pinCache = "0".toCharArray();
    public static Logger log = Logger.getLogger(ITextSigner.class);

    public ITextSigner(byte[] file) {
        config = Configurator.getInstance();
    }

    public void loginCard(char[] pin)
            throws PKCS11Exception, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
        log.info("Reading card ...");
        KeyStore pkcs11Keystore = config.getCardHandler().getPKCS11KeyStore();
        if (pin != null) {
            if (Arrays.equals(pinCache, pin) && pin.length != 6) {
                throw new PKCS11Exception("CKR_ARGUMENTS_BAD");
            } else if (pin.length != 6) {
                throw new PKCS11Exception("CKR_ARGUMENTS_BAD");
            } else if (Arrays.equals(pinCache, pin) && pin.length == 6) {
                throw new PKCS11Exception("CKR_PIN_INCORRECT");
            }
        }
        provider = config.getCardHandler().getProvider();
        log.info("Opening PKCS11 session ...");
        if (pin == null) {
            log.info("Awaiting PIN ...");
        } else {
            log.info("Logging in to PKCS11 session ...");
        }
        pkcs11Keystore.load(null, pin);
        log.info("Cardlogin done!");
        Enumeration aliaes = null;
        aliaes = pkcs11Keystore.aliases();

        Certificate certList[] = new Certificate[pkcs11Keystore.size()];
        ArrayList<Key> keys = new ArrayList<Key>();
        int i = 0;
        log.info("Reading cardcertificates from token...");
        while (aliaes.hasMoreElements()) {
            String label = (String) aliaes.nextElement();
            X509Certificate cert = null;
            try {
                cert = (X509Certificate) pkcs11Keystore.getCertificate(label);
            } catch (Exception e) {
                log.error("Cannot find certificate with label: " + label, e);
            }
            if (label.equals("RUBSIGNCERT")) { //Signcertificate must be at top position in signchain
                certList[0] = cert;
                log.info("'RUBSIGNCERT' added to signchain");
                try {
                    signPrivKey = pkcs11Keystore.getKey(label, null);
                    log.info("Private key found and set for 'RUBSIGNCERT'");
                } catch (Exception e) {
                    log.error("Cannot find private key with label: " + label, e);
                }
            }
            if (label.equals("RUBCACERT")) {
                certList[1] = cert;
                log.info("'RUBCACERT' added to signchain");
            }
            if (label.equals("DFN-Verein PCA Global - G01")) {
                certList[2] = cert;
                log.info("'DFN-Verein PCA Global - G01' added to signchain");
            }
            if (label.equals("Deutsche Telekom Root CA 2")) {
                certList[3] = cert;
                log.info("'Deutsch Telekom Root CA 2' added to signchain");
            }
            i++;
        }
        if (certList.length == 0) {
            throw new PKCS11Exception("NO_RUBSIGNCERT");
        }

        if (signPrivKey == null) {
            throw new PKCS11Exception("NO_RUBSIGNCERT");
        }

        signCert = new ArrayList<Certificate>();
        for (Certificate cert : certList) {
            if (cert != null) {
                signCert.add(cert);
            }
        }
        log.info("Certificate- & keyloading done!");
    }

    public static void handleException(Exception e) {
        if (e instanceof CertificateException) {
            //-110
            DecoratedJOptionPane.showMessageDialog(null,
                    LanguageFactory.getText(LanguageFactory.ITEXTSIGNER_CERTIFICATE_ERROR),
                    LanguageFactory.getText(LanguageFactory.ERROR_HL), JOptionPane.ERROR_MESSAGE);
        } else {
            //-111
            DecoratedJOptionPane.showMessageDialog(null,
                    LanguageFactory.getText(LanguageFactory.ITEXTSIGNER_UNKNOWN_ERROR_DURING_SIGN),
                    LanguageFactory.getText(LanguageFactory.ERROR_HL), JOptionPane.ERROR_MESSAGE);
        }
    }

    public ByteArrayOutputStream doSign(byte[] pdf, Rectangle stampPos, int pageNmbrForStamp) throws IOException,
            DocumentException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        Certificate[] chain = signCert.toArray(new Certificate[0]);

        PdfReader reader = new PdfReader(pdf);
        ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
        PdfStamper stp = PdfStamper.createSignature(reader, byteOS, '\0', null, true);
        PdfSignatureAppearance sap = stp.getSignatureAppearance();
        if (stampPos != null) {
            sap.setVisibleSignature(
                    new com.itextpdf.text.Rectangle(stampPos.x, stampPos.y, stampPos.width, stampPos.height),
                    pageNmbrForStamp, null);
            sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION);
            sap.setAcro6Layers(true);
        }
        //        Siganture Appearance

        PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, new PdfName("adbe.pkcs7.detached"));
        log.info("Creating signature with reason: " + ParamValidator.getInstance().getSignatureReason());
        sap.setReason(ParamValidator.getInstance().getSignatureReason());
        sap.setLocation("Ruhr-Universitt Bochum");
        Image i = Image.getInstance(getClass().getResource("/de/rub/dez6a3/jpdfsigner/resources/images/sign.png"));
        sap.setImage(i);
        sap.setCrypto((PrivateKey) signPrivKey, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
        dic.setReason(ParamValidator.getInstance().getSignatureReason());
        dic.setLocation("Ruhr-Universitt Bochum");
        sap.setCryptoDictionary(dic);
        // preserve some space for the contents
        int contentEstimated = 15000;
        HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
        exc.put(PdfName.CONTENTS, new Integer(contentEstimated * 2 + 2));
        sap.preClose(exc);
        // make the digest
        InputStream data = sap.getRangeStream();
        MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
        byte buf[] = new byte[8192];
        int n;
        while ((n = data.read(buf)) > 0) {
            messageDigest.update(buf, 0, n);
        }
        byte hash[] = messageDigest.digest();
        Calendar cal = Calendar.getInstance();
        // If we add a time stamp:
        TSAClient tsc = new TSAClientBouncyCastle("http://zeitstempel.dfn.de/");
        // Create the signature

        PdfPKCS7 sgn;
        try {
            sgn = new PdfPKCS7((PrivateKey) signPrivKey, chain, null, "SHA1", null, false);
            byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null);
            sgn.update(sh, 0, sh.length);
            byte[] encodedSig = sgn.getEncodedPKCS7(hash, cal, tsc, null);

            if (contentEstimated + 2 < encodedSig.length) {
                throw new DocumentException("Not enough space");
            }

            byte[] paddedSig = new byte[contentEstimated];
            System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
            // Replace the contents
            PdfDictionary dic2 = new PdfDictionary();
            dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
            sap.close(dic2);
        } catch (NoSuchProviderException ex) {
            ex.printStackTrace();
        }
        return byteOS;
    }

    public void setCardHandle(Provider param) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void getSignedDocument() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}