Package br.net.woodstock.rockframework.security.sign.impl

Source Code of br.net.woodstock.rockframework.security.sign.impl.PDFSigner

/*
* This file is part of rockframework.
*
* rockframework 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.
*
* rockframework 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 <http://www.gnu.org/licenses/>;.
*/
package br.net.woodstock.rockframework.security.sign.impl;

import java.io.ByteArrayOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.tsp.TimeStampToken;

import br.net.woodstock.rockframework.core.RockFrameworkVersion;
import br.net.woodstock.rockframework.core.util.Assert;
import br.net.woodstock.rockframework.core.utils.Collections;
import br.net.woodstock.rockframework.core.utils.Conditions;
import br.net.woodstock.rockframework.security.Alias;
import br.net.woodstock.rockframework.security.Identity;
import br.net.woodstock.rockframework.security.digest.DigestType;
import br.net.woodstock.rockframework.security.sign.PKCS7SignatureParameters;
import br.net.woodstock.rockframework.security.sign.Signatory;
import br.net.woodstock.rockframework.security.sign.Signature;
import br.net.woodstock.rockframework.security.sign.SignatureInfo;
import br.net.woodstock.rockframework.security.sign.SignatureType;
import br.net.woodstock.rockframework.security.sign.SignerException;
import br.net.woodstock.rockframework.security.store.CertificateEntry;
import br.net.woodstock.rockframework.security.store.KeyStoreType;
import br.net.woodstock.rockframework.security.store.Store;
import br.net.woodstock.rockframework.security.store.impl.JCAStore;
import br.net.woodstock.rockframework.security.timestamp.TimeStamp;
import br.net.woodstock.rockframework.security.timestamp.impl.BouncyCastleTimeStampHelper;
import br.net.woodstock.rockframework.security.util.BouncyCastleProviderHelper;

import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfDate;
import com.itextpdf.text.pdf.PdfName;
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.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CertificateUtil;
import com.itextpdf.text.pdf.security.CertificateVerification;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
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;

public class PDFSigner extends AbstractSigner {

  private static final long      serialVersionUID    = RockFrameworkVersion.VERSION;

  private static final char      PDF_SIGNATURE_VERSION  = '\0';

  private PKCS7SignatureParameters  parameters;

  public PDFSigner(final PKCS7SignatureParameters parameters) {
    super();
    this.parameters = parameters;
  }

  @Override
  public byte[] sign(final byte[] data) {
    Assert.notNull(this.parameters, "parameters");
    Assert.notNull(data, "data");
    try {
      byte[] currentData = data;
      for (Identity identity : this.parameters.getIdentities()) {
        currentData = this.singleSign(data, identity);
      }
      return currentData;
    } catch (Exception e) {
      throw new SignerException(e);
    }
  }

  private byte[] singleSign(final byte[] data, final Identity identity) {
    Assert.notEmpty(data, "data");
    try {
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

      PrivateKey privateKey = identity.getPrivateKey();
      Certificate[] chain = identity.getChain();
      X509Certificate certificate = (X509Certificate) chain[0];

      DigestType digestType = this.getDigestTypeFromSignature(certificate.getSigAlgName());
      Calendar calendar = Calendar.getInstance();

      PdfReader reader = new PdfReader(data);
      PdfStamper stamper = PdfStamper.createSignature(reader, outputStream, PDFSigner.PDF_SIGNATURE_VERSION, null, true);

      PdfSignatureAppearance appearance = stamper.getSignatureAppearance();

      if (this.parameters.getSignatureInfo() != null) {
        appearance.setContact(this.parameters.getSignatureInfo().getContactInfo());
        appearance.setLocation(this.parameters.getSignatureInfo().getLocation());
        appearance.setReason(this.parameters.getSignatureInfo().getReason());
      }

      appearance.setSignDate(calendar);

      PdfSignature signature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
      signature.setReason(appearance.getReason());
      signature.setLocation(appearance.getLocation());
      signature.setContact(appearance.getContact());
      signature.setDate(new PdfDate(appearance.getSignDate()));

      if ((this.parameters.getSignatureInfo() != null) && (Conditions.isNotEmpty(this.parameters.getSignatureInfo().getName()))) {
        signature.setName(this.parameters.getSignatureInfo().getName());
      } else {
        signature.setName(BouncyCastleProviderHelper.toString(certificate.getSubjectX500Principal()));
      }

      appearance.setCryptoDictionary(signature);

      String providerName = null;
      if (Conditions.isNotEmpty(this.parameters.getProvider())) {
        providerName = this.parameters.getProvider();
      } else {
        providerName = BouncyCastleProviderHelper.PROVIDER_NAME;
      }

      ExternalSignature externalSignature = new PrivateKeySignature(privateKey, digestType.getAlgorithm(), providerName);

      ExternalDigest externalDigest = new BouncyCastleDigest();

      TSAClient tsc = null;
      if (this.parameters.getTimeStampClient() != null) {
        tsc = new DelegateTSAClient(this.parameters.getTimeStampClient(), digestType);
      }

      OcspClient ocsp = null;
      if (Conditions.isNotEmpty(chain)) {
        String ocspUrl = CertificateUtil.getOCSPURL(certificate);
        X509Certificate parentCertificate = null;

        for (Certificate c : chain) {
          if (!certificate.equals(c)) {
            parentCertificate = (X509Certificate) c;
            break;
          }
        }

        if (parentCertificate != null) {
          if ((ocspUrl != null) && (ocspUrl.trim().length() > 0)) {
            ocsp = new OcspClientBouncyCastle();
          }
        }
      }

      MakeSignature.signDetached(appearance, externalDigest, externalSignature, chain, null, ocsp, tsc, 0, CryptoStandard.CMS);

      return outputStream.toByteArray();
    } catch (Exception e) {
      throw new SignerException(e);
    }
  }

  @Override
  public boolean verify(final byte[] data, final byte[] signature) {
    try {
      Signature[] signatures = this.getSignatures(signature);
      if (Conditions.isNotEmpty(signatures)) {
        for (Signature s : signatures) {
          if (!s.getValid().booleanValue()) {
            return false;
          }
        }
      }
      return true;
    } catch (Exception e) {
      throw new SignerException(e);
    }
  }

  @Override
  public Signature[] getSignatures(final byte[] data) {
    try {
      KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
      keystore.load(null, null);

      PdfReader reader = new PdfReader(data);
      AcroFields fields = reader.getAcroFields();
      Collection<Signature> signatures = new ArrayList<Signature>();
      if (fields != null) {
        List<String> list = fields.getSignatureNames();
        if ((list != null) && (!list.isEmpty())) {
          for (String str : list) {
            PdfPKCS7 pk = fields.verifySignature(str);

            PdfString string = fields.getSignatureDictionary(str).getAsString(PdfName.CONTENTS);
            byte[] content = string.getBytes();

            X509Certificate certificate = pk.getSigningCertificate();

            byte[] encoded = content;
            TimeStamp timeStamp = null;
            String location = pk.getLocation();
            String reason = pk.getReason();
            String signName = pk.getSignName();
            Date date = pk.getSignDate().getTime();
            Boolean valid = Boolean.TRUE;
            Signatory signatory = this.toSignatory(certificate);

            Store store = new JCAStore(KeyStoreType.JKS);
            store.add(new CertificateEntry(new Alias(certificate.getSerialNumber().toString()), certificate));

            if (pk.verify()) {
              valid = Boolean.FALSE;
            }

            Object[] fails = CertificateVerification.verifyCertificates(pk.getCertificates(), keystore, null, pk.getSignDate());
            if (Conditions.isNotEmpty(fails)) {
              valid = Boolean.FALSE;
            }

            TimeStampToken timeStampToken = pk.getTimeStampToken();
            if (timeStampToken != null) {
              timeStamp = BouncyCastleTimeStampHelper.toTimeStamp(timeStampToken);
              timeStampToken.getTimeStampInfo();
              if (valid.booleanValue()) {
                boolean ok = pk.verifyTimestampImprint();
                valid = Boolean.valueOf(ok);
              }
            }

            Signature sig = new Signature();
            sig.setDate(date);
            sig.setEncoded(encoded);
            sig.setSignatories(new ArrayList<Signatory>());
            sig.getSignatories().add(signatory);
            sig.setTimeStamp(timeStamp);
            sig.setValid(valid);

            if ((Conditions.isNotEmpty(location)) || (Conditions.isNotEmpty(reason)) || (Conditions.isNotEmpty(signName))) {
              SignatureInfo info = new SignatureInfo(signName, reason, location, null);
              sig.setSignatureInfo(info);
            }

            signatures.add(sig);
          }
        }
      }

      return Collections.toArray(signatures, Signature.class);
    } catch (Exception e) {
      throw new SignerException(e);
    }
  }

  protected Signatory toSignatory(final X509Certificate certificate) {
    X500Principal x500Subject = certificate.getSubjectX500Principal();
    X500Principal x500Issuer = certificate.getIssuerX500Principal();

    String subject = BouncyCastleProviderHelper.toString(x500Subject);
    String issuer = BouncyCastleProviderHelper.toString(x500Issuer);

    Signatory signatory = new Signatory();
    signatory.setCertificate(certificate);
    signatory.setIssuer(issuer);
    signatory.setSubject(subject);
    return signatory;
  }

  protected SignatureType getSignatureType(final String signatureAlgorithm) {
    SignatureType type = SignatureType.getSignType(signatureAlgorithm);
    if (type == null) {
      type = SignatureType.SHA1_RSA;
    }
    return type;
  }

  protected DigestType getDigestTypeFromSignature(final String signatureAlgorithm) {
    SignatureType signatureType = this.getSignatureType(signatureAlgorithm);
    DigestType digestType = signatureType.getDigestType();
    return digestType;
  }

}
TOP

Related Classes of br.net.woodstock.rockframework.security.sign.impl.PDFSigner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.