Example usage for org.apache.pdfbox.pdmodel.interactive.digitalsignature PDSignature getByteRange

List of usage examples for org.apache.pdfbox.pdmodel.interactive.digitalsignature PDSignature getByteRange

Introduction

In this page you can find the example usage for org.apache.pdfbox.pdmodel.interactive.digitalsignature PDSignature getByteRange.

Prototype

public int[] getByteRange() 

Source Link

Document

Read out the byterange from the file.

Usage

From source file:eu.europa.ec.markt.dss.signature.pdf.pdfbox.PdfBoxCMSInfo.java

License:Open Source License

/**
 * @param validationCertPool//from w ww.j  a v a2  s.  c o m
 * @param outerCatalog       the PDF Dict of the outer document, if the PDFDocument in a enclosed revision. Can be null.
 * @param document           the signed PDFDocument
 * @param cms                the CMS bytes (CAdES signature)
 * @param inputStream        the stream of the whole signed document
 * @throws IOException
 */
PdfBoxCMSInfo(CertificatePool validationCertPool, PdfDict outerCatalog, PDDocument document,
        PDSignature signature, byte[] cms, InputStream inputStream) throws DSSException, IOException {
    this.validationCertPool = validationCertPool;
    this.outerCatalog = PdfDssDict.build(outerCatalog);
    this.cms = cms;
    this.location = signature.getLocation();
    this.signingDate = signature.getSignDate() != null ? signature.getSignDate().getTime() : null;
    this.signatureByteRange = signature.getByteRange();
    final COSDictionary cosDictionary = document.getDocumentCatalog().getCOSDictionary();
    final PdfBoxDict documentDict = new PdfBoxDict(cosDictionary, document);
    documentDictionary = PdfDssDict.build(documentDict);
    try {
        if (cms == null) {
            // due to not very good revision extracting
            throw new DSSPadesNoSignatureFound();
        }
        signedBytes = signature.getSignedContent(inputStream);
    } catch (IOException e) {
        throw new DSSException(e);
    }
}

From source file:eu.europa.ec.markt.dss.signature.pdf.pdfbox.PdfBoxSignatureService.java

License:Open Source License

/**
 * @param validationCertPool/*from  w w  w  .ja v a  2  s  .  co m*/
 * @param byteRangeMap
 * @param outerCatalog       the PdfDictionary of the document that enclose the document stored in the input InputStream
 * @param input              the Pdf bytes to open as a PDF
 * @return
 * @throws DSSException
 */
private Set<PdfSignatureOrDocTimestampInfo> validateSignatures(CertificatePool validationCertPool,
        Map<String, Set<PdfSignatureOrDocTimestampInfo>> byteRangeMap, PdfDict outerCatalog, InputStream input)
        throws DSSException {
    Set<PdfSignatureOrDocTimestampInfo> signaturesFound = new LinkedHashSet<PdfSignatureOrDocTimestampInfo>();
    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    PDDocument doc = null;
    try {
        DSSUtils.copy(input, buffer);

        doc = PDDocument.load(new ByteArrayInputStream(buffer.toByteArray()));
        final PdfDict catalog = new PdfBoxDict(doc.getDocumentCatalog().getCOSDictionary(), doc);

        final List<PDSignature> signatureDictionaries = doc.getSignatureDictionaries();
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found {} signatures in PDF dictionary of PDF sized {} bytes",
                    signatureDictionaries.size(), buffer.size());
        }
        for (int i = 0; i < signatureDictionaries.size(); i++) {
            final PDSignature signature = signatureDictionaries.get(i);
            /**
             * SubFilter Name (Required) The value of SubFilter identifies the format of the data contained in the stream.
             * A conforming reader may use any conforming signature handler that supports the specified format.
             * When the value of Type is DocTimestamp, the value of SubFilter shall be ETSI.RFC3161.
             */
            final String subFilter = signature.getSubFilter();

            byte[] cms = new PdfBoxDict(signature.getDictionary(), doc).get("Contents");

            PdfSignatureOrDocTimestampInfo signatureInfo;
            try {
                if (PdfBoxDocTimeStampService.SUB_FILTER_ETSI_RFC3161.getName().equals(subFilter)) {
                    signatureInfo = PdfSignatureFactory.createPdfTimestampInfo(validationCertPool, outerCatalog,
                            doc, signature, cms, buffer);
                } else {
                    signatureInfo = PdfSignatureFactory.createPdfSignatureInfo(validationCertPool, outerCatalog,
                            doc, signature, cms, buffer);
                }
            } catch (PdfSignatureOrDocTimestampInfo.DSSPadesNoSignatureFound e) {
                LOG.debug("No signature found in signature Dictionary:Content", e);
                continue;
            }

            signatureInfo = signatureAlreadyInListOrSelf(signaturesFound, signatureInfo);

            // should store in memory this byte range with a list of signature found there
            final String byteRange = Arrays.toString(signature.getByteRange());
            Set<PdfSignatureOrDocTimestampInfo> innerSignaturesFound = byteRangeMap.get(byteRange);
            if (innerSignaturesFound == null) {
                // Recursive call to find inner signatures in the byte range covered by this signature. Deep first search.
                final byte[] originalBytes = signatureInfo.getOriginalBytes();
                if (LOG.isDebugEnabled()) {
                    LOG.debug(
                            "Searching signature in the previous revision of the document, size of revision is {} bytes",
                            originalBytes.length);
                }
                innerSignaturesFound = validateSignatures(validationCertPool, byteRangeMap, catalog,
                        new ByteArrayInputStream(originalBytes));
                byteRangeMap.put(byteRange, innerSignaturesFound);
            }

            // need to mark a signature as included inside another one. It's needed to link timestamp signature with the signatures covered by the timestamp.
            for (PdfSignatureOrDocTimestampInfo innerSignature : innerSignaturesFound) {
                innerSignature = signatureAlreadyInListOrSelf(signaturesFound, innerSignature);
                signaturesFound.add(innerSignature);
                innerSignature.addOuterSignature(signatureInfo);
            }

            signaturesFound.add(signatureInfo);
        }
        return signaturesFound;
    } catch (IOException up) {
        LOG.error("Error loading buffer of size {}", buffer.size(), up);
        // ignore error when loading signatures
        return signaturesFound;
    } finally {
        DSSPDFUtils.close(doc);
    }
}

From source file:eu.europa.ejusticeportal.dss.controller.signature.PdfUtils.java

License:EUPL

private static byte[] getOriginalBytes(PDDocument doc, byte[] signedBytes) throws IOException {
    PDSignature signature = doc.getSignatureDictionaries().get(0);
    final int length = signature.getByteRange()[1];
    final byte[] result = new byte[length];
    System.arraycopy(signedBytes, 0, result, 0, length);
    return result;
}

From source file:eu.europa.esig.dss.pades.InfiniteLoopDSS621Test.java

License:Open Source License

/**
 * These signatures are invalid because of non ordered signed attributes
 *///from  w  w  w .  j a va2s.c  o m
@Test
public void manualTest() throws Exception {

    File pdfFile = new File(FILE_PATH);

    FileInputStream fis = new FileInputStream(pdfFile);
    byte[] pdfBytes = IOUtils.toByteArray(fis);

    PDDocument document = PDDocument.load(pdfFile);
    List<PDSignature> signatures = document.getSignatureDictionaries();
    assertEquals(6, signatures.size());

    int idx = 0;
    for (PDSignature pdSignature : signatures) {
        byte[] contents = pdSignature.getContents(pdfBytes);
        byte[] signedContent = pdSignature.getSignedContent(pdfBytes);

        logger.info("Byte range : " + Arrays.toString(pdSignature.getByteRange()));

        IOUtils.write(contents, new FileOutputStream("target/sig" + (idx++) + ".p7s"));

        ASN1InputStream asn1sInput = new ASN1InputStream(contents);
        ASN1Sequence asn1Seq = (ASN1Sequence) asn1sInput.readObject();

        logger.info("SEQ : " + asn1Seq.toString());

        ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(asn1Seq.getObjectAt(0));
        assertEquals(PKCSObjectIdentifiers.signedData, oid);

        SignedData signedData = SignedData
                .getInstance(DERTaggedObject.getInstance(asn1Seq.getObjectAt(1)).getObject());

        ASN1Set digestAlgorithmSet = signedData.getDigestAlgorithms();
        ASN1ObjectIdentifier oidDigestAlgo = ASN1ObjectIdentifier
                .getInstance(ASN1Sequence.getInstance(digestAlgorithmSet.getObjectAt(0)).getObjectAt(0));
        DigestAlgorithm digestAlgorithm = DigestAlgorithm.forOID(oidDigestAlgo.getId());
        logger.info("DIGEST ALGO : " + digestAlgorithm);

        ContentInfo encapContentInfo = signedData.getEncapContentInfo();
        ASN1ObjectIdentifier contentTypeOID = encapContentInfo.getContentType();
        logger.info("ENCAPSULATED CONTENT INFO TYPE : " + contentTypeOID);

        if (!PKCSObjectIdentifiers.id_ct_TSTInfo.equals(contentTypeOID)) { // If not timestamp
            assertEquals(PKCSObjectIdentifiers.data, contentTypeOID);

            ASN1Encodable content = encapContentInfo.getContent();
            logger.info("ENCAPSULATED CONTENT INFO CONTENT : " + content);
            assertNull(content);

            List<X509Certificate> certificates = extractCertificates(signedData);

            ASN1Set signerInfosAsn1 = signedData.getSignerInfos();
            logger.info("SIGNER INFO ASN1 : " + signerInfosAsn1.toString());
            SignerInfo signedInfo = SignerInfo
                    .getInstance(ASN1Sequence.getInstance(signerInfosAsn1.getObjectAt(0)));

            ASN1Set authenticatedAttributeSet = signedInfo.getAuthenticatedAttributes();
            logger.info("AUTHENTICATED ATTR : " + authenticatedAttributeSet);

            Attribute attributeDigest = null;
            for (int i = 0; i < authenticatedAttributeSet.size(); i++) {
                Attribute attribute = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(i));
                if (PKCSObjectIdentifiers.pkcs_9_at_messageDigest.equals(attribute.getAttrType())) {
                    attributeDigest = attribute;
                    break;
                }
            }

            assertNotNull(attributeDigest);

            ASN1OctetString asn1ObjString = ASN1OctetString
                    .getInstance(attributeDigest.getAttrValues().getObjectAt(0));
            String embeddedDigest = Base64.encodeBase64String(asn1ObjString.getOctets());
            logger.info("MESSAGE DIGEST : " + embeddedDigest);

            byte[] digestSignedContent = DSSUtils.digest(digestAlgorithm, signedContent);
            String computedDigestSignedContentEncodeBase64 = Base64.encodeBase64String(digestSignedContent);
            logger.info("COMPUTED DIGEST SIGNED CONTENT BASE64 : " + computedDigestSignedContentEncodeBase64);
            assertEquals(embeddedDigest, computedDigestSignedContentEncodeBase64);

            SignerIdentifier sid = signedInfo.getSID();
            logger.info("SIGNER IDENTIFIER : " + sid.getId());

            IssuerAndSerialNumber issuerAndSerialNumber = IssuerAndSerialNumber
                    .getInstance(signedInfo.getSID());
            ASN1Integer signerSerialNumber = issuerAndSerialNumber.getSerialNumber();
            logger.info("ISSUER AND SN : " + issuerAndSerialNumber.getName() + " " + signerSerialNumber);

            BigInteger serial = issuerAndSerialNumber.getSerialNumber().getValue();
            X509Certificate signerCertificate = null;
            for (X509Certificate x509Certificate : certificates) {
                if (serial.equals(x509Certificate.getSerialNumber())) {
                    signerCertificate = x509Certificate;
                }
            }
            assertNotNull(signerCertificate);

            String algorithm = signerCertificate.getPublicKey().getAlgorithm();
            EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.forName(algorithm);

            ASN1OctetString encryptedInfoOctedString = signedInfo.getEncryptedDigest();
            String signatureValue = Hex.toHexString(encryptedInfoOctedString.getOctets());

            logger.info("SIGNATURE VALUE : " + signatureValue);

            Cipher cipher = Cipher.getInstance(encryptionAlgorithm.getName());
            cipher.init(Cipher.DECRYPT_MODE, signerCertificate);
            byte[] decrypted = cipher.doFinal(encryptedInfoOctedString.getOctets());

            ASN1InputStream inputDecrypted = new ASN1InputStream(decrypted);

            ASN1Sequence seqDecrypt = (ASN1Sequence) inputDecrypted.readObject();
            logger.info("DECRYPTED : " + seqDecrypt);

            DigestInfo digestInfo = new DigestInfo(seqDecrypt);
            assertEquals(oidDigestAlgo, digestInfo.getAlgorithmId().getAlgorithm());

            String decryptedDigestEncodeBase64 = Base64.encodeBase64String(digestInfo.getDigest());
            logger.info("DECRYPTED BASE64 : " + decryptedDigestEncodeBase64);

            byte[] encoded = authenticatedAttributeSet.getEncoded();
            byte[] digest = DSSUtils.digest(digestAlgorithm, encoded);
            String computedDigestFromSignatureEncodeBase64 = Base64.encodeBase64String(digest);
            logger.info("COMPUTED DIGEST FROM SIGNATURE BASE64 : " + computedDigestFromSignatureEncodeBase64);

            assertEquals(decryptedDigestEncodeBase64, computedDigestFromSignatureEncodeBase64);

            IOUtils.closeQuietly(inputDecrypted);

        }

        IOUtils.closeQuietly(asn1sInput);
    }

    IOUtils.closeQuietly(fis);
    document.close();
}

From source file:eu.europa.esig.dss.pades.signature.PAdESLevelBTest.java

License:Open Source License

@Override
protected void onDocumentSigned(byte[] byteArray) {

    try {//from ww  w  .  j ava2  s  . c  o  m
        InputStream inputStream = new ByteArrayInputStream(byteArray);

        PDDocument document = PDDocument.load(inputStream);
        List<PDSignature> signatures = document.getSignatureDictionaries();
        assertEquals(1, signatures.size());

        for (PDSignature pdSignature : signatures) {
            byte[] contents = pdSignature.getContents(byteArray);
            byte[] signedContent = pdSignature.getSignedContent(byteArray);

            logger.info("Byte range : " + Arrays.toString(pdSignature.getByteRange()));

            // IOUtils.write(contents, new FileOutputStream("sig.p7s"));

            ASN1InputStream asn1sInput = new ASN1InputStream(contents);
            ASN1Sequence asn1Seq = (ASN1Sequence) asn1sInput.readObject();

            logger.info("SEQ : " + asn1Seq.toString());

            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(asn1Seq.getObjectAt(0));
            assertEquals(PKCSObjectIdentifiers.signedData, oid);

            SignedData signedData = SignedData
                    .getInstance(DERTaggedObject.getInstance(asn1Seq.getObjectAt(1)).getObject());

            ASN1Set digestAlgorithmSet = signedData.getDigestAlgorithms();
            ASN1ObjectIdentifier oidDigestAlgo = ASN1ObjectIdentifier
                    .getInstance(ASN1Sequence.getInstance(digestAlgorithmSet.getObjectAt(0)).getObjectAt(0));
            DigestAlgorithm digestAlgorithm = DigestAlgorithm.forOID(oidDigestAlgo.getId());
            logger.info("DIGEST ALGO : " + digestAlgorithm);

            ContentInfo encapContentInfo = signedData.getEncapContentInfo();
            ASN1ObjectIdentifier contentTypeOID = encapContentInfo.getContentType();
            logger.info("ENCAPSULATED CONTENT INFO TYPE : " + contentTypeOID);
            assertEquals(PKCSObjectIdentifiers.data, contentTypeOID);

            ASN1Encodable content = encapContentInfo.getContent();
            logger.info("ENCAPSULATED CONTENT INFO CONTENT : " + content);
            assertNull(content);

            List<X509Certificate> certificates = extractCertificates(signedData);

            ASN1Set signerInfosAsn1 = signedData.getSignerInfos();
            logger.info("SIGNER INFO ASN1 : " + signerInfosAsn1.toString());
            SignerInfo signedInfo = SignerInfo
                    .getInstance(ASN1Sequence.getInstance(signerInfosAsn1.getObjectAt(0)));

            ASN1Set authenticatedAttributeSet = signedInfo.getAuthenticatedAttributes();
            logger.info("AUTHENTICATED ATTR : " + authenticatedAttributeSet);

            List<ASN1ObjectIdentifier> attributeOids = new ArrayList<ASN1ObjectIdentifier>();
            int previousSize = 0;
            for (int i = 0; i < authenticatedAttributeSet.size(); i++) {
                Attribute attribute = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(i));
                ASN1ObjectIdentifier attrTypeOid = attribute.getAttrType();
                attributeOids.add(attrTypeOid);
                int size = attrTypeOid.getEncoded().length + attribute.getEncoded().length;
                assertTrue(size >= previousSize);

                previousSize = size;
            }
            logger.info("List of OID for Auth Attrb : " + attributeOids);

            Attribute attributeDigest = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(1));
            assertEquals(PKCSObjectIdentifiers.pkcs_9_at_messageDigest, attributeDigest.getAttrType());

            ASN1OctetString asn1ObjString = ASN1OctetString
                    .getInstance(attributeDigest.getAttrValues().getObjectAt(0));
            String embeddedDigest = Base64.encodeBase64String(asn1ObjString.getOctets());
            logger.info("MESSAGE DIGEST : " + embeddedDigest);

            byte[] digestSignedContent = DSSUtils.digest(digestAlgorithm, signedContent);
            String computedDigestSignedContentEncodeBase64 = Base64.encodeBase64String(digestSignedContent);
            logger.info("COMPUTED DIGEST SIGNED CONTENT BASE64 : " + computedDigestSignedContentEncodeBase64);
            assertEquals(embeddedDigest, computedDigestSignedContentEncodeBase64);

            SignerIdentifier sid = signedInfo.getSID();
            logger.info("SIGNER IDENTIFIER : " + sid.getId());

            IssuerAndSerialNumber issuerAndSerialNumber = IssuerAndSerialNumber
                    .getInstance(signedInfo.getSID());
            ASN1Integer signerSerialNumber = issuerAndSerialNumber.getSerialNumber();
            logger.info("ISSUER AND SN : " + issuerAndSerialNumber.getName() + " " + signerSerialNumber);

            BigInteger serial = issuerAndSerialNumber.getSerialNumber().getValue();
            X509Certificate signerCertificate = null;
            for (X509Certificate x509Certificate : certificates) {
                if (serial.equals(x509Certificate.getSerialNumber())) {
                    signerCertificate = x509Certificate;
                }
            }
            assertNotNull(signerCertificate);

            String algorithm = signerCertificate.getPublicKey().getAlgorithm();
            EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.forName(algorithm);

            ASN1OctetString encryptedInfoOctedString = signedInfo.getEncryptedDigest();
            String signatureValue = Hex.toHexString(encryptedInfoOctedString.getOctets());

            logger.info("SIGNATURE VALUE : " + signatureValue);

            Cipher cipher = Cipher.getInstance(encryptionAlgorithm.getName());
            cipher.init(Cipher.DECRYPT_MODE, signerCertificate);
            byte[] decrypted = cipher.doFinal(encryptedInfoOctedString.getOctets());

            ASN1InputStream inputDecrypted = new ASN1InputStream(decrypted);

            ASN1Sequence seqDecrypt = (ASN1Sequence) inputDecrypted.readObject();
            logger.info("DECRYPTED : " + seqDecrypt);

            DigestInfo digestInfo = new DigestInfo(seqDecrypt);
            assertEquals(oidDigestAlgo, digestInfo.getAlgorithmId().getAlgorithm());

            String decryptedDigestEncodeBase64 = Base64.encodeBase64String(digestInfo.getDigest());
            logger.info("DECRYPTED BASE64 : " + decryptedDigestEncodeBase64);

            byte[] encoded = authenticatedAttributeSet.getEncoded();
            byte[] digest = DSSUtils.digest(digestAlgorithm, encoded);
            String computedDigestFromSignatureEncodeBase64 = Base64.encodeBase64String(digest);
            logger.info("COMPUTED DIGEST FROM SIGNATURE BASE64 : " + computedDigestFromSignatureEncodeBase64);

            assertEquals(decryptedDigestEncodeBase64, computedDigestFromSignatureEncodeBase64);

            IOUtils.closeQuietly(inputDecrypted);
            IOUtils.closeQuietly(asn1sInput);
        }

        IOUtils.closeQuietly(inputStream);
        document.close();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
        fail(e.getMessage());
    }
}

From source file:eu.europa.esig.dss.pdf.pdfbox.PdfBoxCMSInfo.java

License:Open Source License

/**
 *
 * @param signature The signature object
 * @param dssDictionary the DSS dictionary
 * @param cms the signature binary/*from   w w  w. j  a  va2  s . co  m*/
 * @param signedContent the signed content
 */
PdfBoxCMSInfo(PDSignature signature, PdfDssDict dssDictionary, byte[] cms, byte[] signedContent) {
    this.cms = cms;
    this.location = signature.getLocation();
    this.reason = signature.getReason();
    this.contactInfo = signature.getContactInfo();
    this.subFilter = signature.getSubFilter();
    this.signingDate = signature.getSignDate() != null ? signature.getSignDate().getTime() : null;
    this.signatureByteRange = signature.getByteRange();
    this.dssDictionary = dssDictionary;
    this.signedBytes = signedContent;
}

From source file:eu.europa.esig.dss.pdf.pdfbox.PdfBoxSignatureService.java

License:Open Source License

private List<PdfSignatureOrDocTimestampInfo> getSignatures(CertificatePool validationCertPool,
        byte[] originalBytes) {
    List<PdfSignatureOrDocTimestampInfo> signatures = new ArrayList<PdfSignatureOrDocTimestampInfo>();
    ByteArrayInputStream bais = null;
    PDDocument doc = null;/* www.  ja  va  2  s  .  co m*/
    try {

        bais = new ByteArrayInputStream(originalBytes);
        doc = PDDocument.load(bais);

        List<PDSignature> pdSignatures = doc.getSignatureDictionaries();
        if (CollectionUtils.isNotEmpty(pdSignatures)) {
            logger.debug("{} signature(s) found", pdSignatures.size());

            PdfDict catalog = new PdfBoxDict(doc.getDocumentCatalog().getCOSDictionary(), doc);
            PdfDssDict dssDictionary = PdfDssDict.extract(catalog);

            for (PDSignature signature : pdSignatures) {
                String subFilter = signature.getSubFilter();
                byte[] cms = signature.getContents(originalBytes);

                if (StringUtils.isEmpty(subFilter) || ArrayUtils.isEmpty(cms)) {
                    logger.warn("Wrong signature with empty subfilter or cms.");
                    continue;
                }

                byte[] signedContent = signature.getSignedContent(originalBytes);
                int[] byteRange = signature.getByteRange();

                PdfSignatureOrDocTimestampInfo signatureInfo = null;
                if (PdfBoxDocTimeStampService.SUB_FILTER_ETSI_RFC3161.getName().equals(subFilter)) {
                    boolean isArchiveTimestamp = false;

                    // LT or LTA
                    if (dssDictionary != null) {
                        // check is DSS dictionary already exist
                        if (isDSSDictionaryPresentInPreviousRevision(
                                getOriginalBytes(byteRange, signedContent))) {
                            isArchiveTimestamp = true;
                        }
                    }

                    signatureInfo = new PdfBoxDocTimestampInfo(validationCertPool, signature, dssDictionary,
                            cms, signedContent, isArchiveTimestamp);
                } else {
                    signatureInfo = new PdfBoxSignatureInfo(validationCertPool, signature, dssDictionary, cms,
                            signedContent);
                }

                if (signatureInfo != null) {
                    signatures.add(signatureInfo);
                }
            }
            Collections.sort(signatures, new PdfSignatureOrDocTimestampInfoComparator());
            linkSignatures(signatures);

            for (PdfSignatureOrDocTimestampInfo sig : signatures) {
                logger.debug("Signature " + sig.uniqueId() + " found with byteRange "
                        + Arrays.toString(sig.getSignatureByteRange()) + " (" + sig.getSubFilter() + ")");
            }
        }

    } catch (Exception e) {
        logger.warn("Cannot analyze signatures : " + e.getMessage(), e);
    } finally {
        IOUtils.closeQuietly(bais);
        IOUtils.closeQuietly(doc);
    }

    return signatures;
}