/******************************************************************************* * Copyright 2014 by E-Government Innovation Center EGIZ, Graz, Austria * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a * joint initiative of the Federal Chancellery Austria and Graz University of * Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. ******************************************************************************/ package at.gv.egiz.pdfas.sigs.pades; import iaik.asn1.ASN1Object; import iaik.asn1.CodingException; import iaik.asn1.ObjectID; import iaik.asn1.SEQUENCE; import iaik.asn1.UTF8String; import iaik.asn1.structures.AlgorithmID; import iaik.asn1.structures.Attribute; import iaik.asn1.structures.ChoiceOfTime; import iaik.cms.ContentInfo; import iaik.cms.IssuerAndSerialNumber; import iaik.cms.SignedData; import iaik.cms.SignerInfo; import iaik.smime.ess.ESSCertID; import iaik.smime.ess.ESSCertIDv2; import iaik.x509.X509Certificate; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.pdfas.common.exceptions.PdfAsException; import at.gv.egiz.pdfas.common.exceptions.PdfAsSignatureException; import at.gv.egiz.pdfas.lib.api.sign.IPlainSigner; import at.gv.egiz.pdfas.lib.api.sign.SignParameter; import at.gv.egiz.pdfas.lib.util.CertificateUtils; public class PAdESSignerKeystore implements IPlainSigner { @SuppressWarnings("unused") private static final Logger logger = LoggerFactory .getLogger(PAdESSignerKeystore.class); PrivateKey privKey; X509Certificate cert; public PAdESSignerKeystore(String file, String alias, String kspassword, String keypassword, String type) throws PdfAsException { try { KeyStore ks = KeyStore.getInstance(type); ks.load(new FileInputStream(file), kspassword.toCharArray()); privKey = (PrivateKey) ks.getKey(alias, keypassword.toCharArray()); cert = new X509Certificate(ks.getCertificate(alias).getEncoded()); } catch (Throwable e) { throw new PdfAsException("error.pdf.sig.02", e); } } public X509Certificate getCertificate(SignParameter parameter) { return cert; } private void setMimeTypeAttrib(List attributes, String mimeType) { String oidStr = "0.4.0.1733.2.1"; String name = "mime-type"; ObjectID mimeTypeOID = new ObjectID(oidStr, name); Attribute mimeTypeAtt = new Attribute(mimeTypeOID, new ASN1Object[] {new UTF8String(mimeType)}); attributes.add(mimeTypeAtt); } private void setContentTypeAttrib(List attributes) { Attribute contentType = new Attribute(ObjectID.contentType, new ASN1Object[] {ObjectID.cms_data}); attributes.add(contentType); } private void setSigningCertificateAttrib(List attributes, X509Certificate signingCertificate) throws CertificateException, NoSuchAlgorithmException, CodingException { ObjectID id; ASN1Object value = new SEQUENCE(); AlgorithmID[] algorithms = CertificateUtils.getAlgorithmIDs(signingCertificate); if (algorithms[1].equals(AlgorithmID.sha1)) { id = ObjectID.signingCertificate; value.addComponent(new ESSCertID(signingCertificate, true).toASN1Object()); } else { id = ObjectID.signingCertificateV2; value.addComponent(new ESSCertIDv2(algorithms[1], signingCertificate, true).toASN1Object()); } ASN1Object signingCert = new SEQUENCE(); signingCert.addComponent(value); Attribute signingCertificateAttrib = new Attribute(id, new ASN1Object[] {signingCert}); attributes.add(signingCertificateAttrib); } private void setSigningTimeAttrib(List attributes, Date date) { Attribute signingTime = new Attribute(ObjectID.signingTime, new ASN1Object[] {new ChoiceOfTime(date).toASN1Object()}); attributes.add(signingTime); } private void setAttributes(String mimeType, X509Certificate signingCertificate, Date signingTime, SignerInfo signerInfo) throws CertificateException, NoSuchAlgorithmException, CodingException { List attributes = new ArrayList(); setMimeTypeAttrib(attributes, mimeType); setContentTypeAttrib(attributes); setSigningCertificateAttrib(attributes, signingCertificate); setSigningTimeAttrib(attributes, signingTime); Attribute[] attributeArray = attributes.toArray(new Attribute[attributes.size()]); signerInfo.setSignedAttributes(attributeArray); } public byte[] sign(byte[] input, int[] byteRange, SignParameter parameter) throws PdfAsException { try { logger.info("Creating PAdES signature."); IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(cert); AlgorithmID[] algorithms = CertificateUtils.getAlgorithmIDs(cert); SignerInfo signer1 = new SignerInfo(issuer, algorithms[1], algorithms[0], privKey); SignedData si = new SignedData(input, SignedData.EXPLICIT); si.addCertificates(new Certificate[] { cert }); setAttributes("application/pdf", cert, new Date(), signer1); si.addSignerInfo(signer1); InputStream dataIs = si.getInputStream(); byte[] buf = new byte[1024]; @SuppressWarnings("unused") int r; while ((r = dataIs.read(buf)) > 0) ; // skip data ContentInfo ci = new ContentInfo(si); return ci.getEncoded(); } catch (NoSuchAlgorithmException e) { throw new PdfAsSignatureException("error.pdf.sig.01", e); } catch (iaik.cms.CMSException e) { throw new PdfAsSignatureException("error.pdf.sig.01", e); } catch (IOException e) { throw new PdfAsSignatureException("error.pdf.sig.01", e); } catch (CertificateException e) { throw new PdfAsSignatureException("error.pdf.sig.01", e); } catch (CodingException e) { throw new PdfAsSignatureException("error.pdf.sig.01", e); } } public String getPDFSubFilter() { return PDSignature.SUBFILTER_ETSI_CADES_DETACHED.getName(); } public String getPDFFilter() { return PDSignature.FILTER_ADOBE_PPKLITE.getName(); } }