Index: examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java
===================================================================
--- examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java	(revision 1558346)
+++ examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java	(working copy)
@@ -33,6 +33,7 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CollectionCertStoreParameters;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Enumeration;
@@ -44,232 +45,338 @@
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.TSACreator;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.cms.Attribute;
+import org.bouncycastle.asn1.cms.AttributeTable;
+import org.bouncycastle.asn1.cms.Attributes;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.CMSProcessable;
 import org.bouncycastle.cms.CMSSignedData;
 import org.bouncycastle.cms.CMSSignedDataGenerator;
 import org.bouncycastle.cms.CMSSignedGenerator;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.SignerInformationStore;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.OperatorCreationException;
 
 /**
- * <p>This is an example for singing a pdf with bouncy castle.</p>
- * <p>A keystore can be created with the java keytool 
- * (e.g. keytool -genkeypair -storepass 123456 -storetype pkcs12 -alias test -validity 365 -v -keyalg RSA -keystore keystore.p12 ) 
+ * <p>
+ * This is an example for singing a pdf with bouncy castle.
  * </p>
+ * <p>
+ * A keystore can be created with the java keytool (e.g. keytool -genkeypair -storepass 123456 -storetype pkcs12 -alias
+ * test -validity 365 -v -keyalg RSA -keystore keystore.p12 )
+ * </p>
  * 
- * @author Thomas Chojecki
+ * @author Thomas Chojecki and Vakhtang Koroghlishvili (Gogebashvili)
  * 
  */
 public class CreateSignature implements SignatureInterface
 {
 
-  private static BouncyCastleProvider provider = new BouncyCastleProvider();
+    private static BouncyCastleProvider provider = new BouncyCastleProvider();
 
-  private PrivateKey privKey;
+    private PrivateKey privKey;
 
-  private Certificate[] cert;
+    private Certificate[] cert;
 
-  private SignatureOptions options;
-  
-  /**
-   * Initialize the signature creator with a keystore (pkcs12) and pin that
-   * should be used for the signature.
-   * 
-   * @param keystore
-   *          is a pkcs12 keystore.
-   * @param pin
-   *          is the pin for the keystore / private key
-   */
-  public CreateSignature(KeyStore keystore, char[] pin)
-  {
-    try
+    private SignatureOptions options;
+
+    private TSACreator tsaCreator;
+
+    public static final String SHA_256_IDENTIFIER = "2.16.840.1.101.3.4.2.1";
+
+    /**
+     * Initialize the signature creator with a keystore (pkcs12) and pin that should be used for the signature.
+     * 
+     * @param keystore
+     *            is a pkcs12 keystore.
+     * @param pin
+     *            is the pin for the keystore / private key
+     */
+    public CreateSignature(KeyStore keystore, char[] pin)
     {
-      /*
-       * grabs the first alias from the keystore and get the private key. An
-       * alternative method or constructor could be used for setting a specific
-       * alias that should be used.
-       */
-      Enumeration<String> aliases = keystore.aliases();
-      String alias = null;
-      if (aliases.hasMoreElements())
-      {
-          alias = aliases.nextElement();
-      }
-      else
-      {
-          throw new RuntimeException("Could not find alias");
-      }
-      privKey = (PrivateKey) keystore.getKey(alias, pin);
-      cert = keystore.getCertificateChain(alias);
+        try
+        {
+            /*
+             * grabs the first alias from the keystore and get the private key. An alternative method or constructor
+             * could be used for setting a specific alias that should be used.
+             */
+            Enumeration<String> aliases = keystore.aliases();
+            String alias = null;
+            if (aliases.hasMoreElements())
+            {
+                alias = aliases.nextElement();
+            }
+            else
+            {
+                throw new RuntimeException("Could not find alias");
+            }
+            privKey = (PrivateKey) keystore.getKey(alias, pin);
+            cert = keystore.getCertificateChain(alias);
+        }
+        catch (KeyStoreException e)
+        {
+            e.printStackTrace();
+        }
+        catch (UnrecoverableKeyException e)
+        {
+            System.err.println("Could not extract private key.");
+            e.printStackTrace();
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            System.err.println("Unknown algorithm.");
+            e.printStackTrace();
+        }
     }
-    catch (KeyStoreException e)
+
+    /**
+     * Signs the given pdf file.
+     * 
+     * @param document
+     *            is the pdf document
+     * @param tsaCreator
+     *            is for tsa time
+     * @return the signed pdf document
+     * @throws IOException
+     * @throws COSVisitorException
+     * @throws SignatureException
+     */
+    public File signPDF(File document, TSACreator tsaCreator) throws IOException, COSVisitorException,
+            SignatureException
     {
-      e.printStackTrace();
+
+        if (tsaCreator != null)
+        {
+            this.tsaCreator = tsaCreator;
+        }
+        byte[] buffer = new byte[8 * 1024];
+        if (document == null || !document.exists())
+        {
+            new RuntimeException("Document for signing does not exist");
+        }
+
+        // creating output document and prepare the IO streams.
+        String name = document.getName();
+        String substring = name.substring(0, name.lastIndexOf("."));
+
+        File outputDocument = new File(document.getParent(), substring + "_signed.pdf");
+        FileInputStream fis = new FileInputStream(document);
+        FileOutputStream fos = new FileOutputStream(outputDocument);
+
+        int c;
+        while ((c = fis.read(buffer)) != -1)
+        {
+            fos.write(buffer, 0, c);
+        }
+        fis.close();
+        fis = new FileInputStream(outputDocument);
+
+        // load document
+        PDDocument doc = PDDocument.load(document);
+
+        // create signature dictionary
+        PDSignature signature = new PDSignature();
+        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
+        // subfilter for basic and PAdES Part 2 signatures
+        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
+        signature.setName("signer name");
+        signature.setLocation("signer location");
+        signature.setReason("reason for signature");
+
+        // the signing date, needed for valid signature
+        signature.setSignDate(Calendar.getInstance());
+
+        // register signature dictionary and sign interface
+        if (options == null)
+        {
+            doc.addSignature(signature, this);
+        }
+        else
+        {
+            doc.addSignature(signature, this, options);
+        }
+
+        // write incremental (only for signing purpose)
+        doc.saveIncremental(fis, fos);
+
+        return outputDocument;
     }
-    catch (UnrecoverableKeyException e)
+
+    /**
+     * <p>
+     * SignatureInterface implementation.
+     * </p>
+     * 
+     * <p>
+     * This method will be called from inside of the pdfbox and create the pkcs7 signature. The given InputStream
+     * contains the bytes that are providen by the byte range.
+     * </p>
+     * 
+     * <p>
+     * This method is for internal use only.
+     * </p>
+     * 
+     * <p>
+     * Here the user should use his favorite cryptographic library and implement a pkcs7 signature creation.
+     * </p>
+     */
+    public byte[] sign(InputStream content) throws SignatureException, IOException
     {
-      System.err.println("Could not extract private key.");
-      e.printStackTrace();
+        CMSProcessableInputStream input = new CMSProcessableInputStream(content);
+        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+        // CertificateChain
+        List<Certificate> certList = Arrays.asList(cert);
+
+        CertStore certStore = null;
+        try
+        {
+            certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), provider);
+            gen.addSigner(privKey, (X509Certificate) certList.get(0), CMSSignedGenerator.DIGEST_SHA256);
+            gen.addCertificatesAndCRLs(certStore);
+            CMSSignedData signedData = gen.generate(input, false, provider);
+
+            CMSSignedData data = signedData;
+
+            if (tsaCreator != null)
+            {
+                data = extendSignedData(signedData, content);
+            }
+
+            return data.getEncoded();
+
+        }
+        catch (Exception e)
+        {
+            // should be handled
+            System.err.println("Error while creating pkcs7 signature.");
+            e.printStackTrace();
+        }
+        throw new RuntimeException("Problem while preparing signature");
     }
-    catch (NoSuchAlgorithmException e)
-    {
-      System.err.println("Unknown algorithm.");
-      e.printStackTrace();
-    }
-  }
-  
-  
 
-  /**
-   * Signs the given pdf file.
-   * 
-   * @param document is the pdf document
-   * @return the signed pdf document
-   * @throws IOException 
-   * @throws COSVisitorException
-   * @throws SignatureException
-   */
-  public File signPDF(File document) throws IOException, COSVisitorException,
-      SignatureException
-  {
-    byte[] buffer = new byte[8 * 1024];
-    if (document == null || !document.exists())
+    /**
+     * We just extend CMS signed Data
+     * 
+     * @param signedData -Generated CMS signed data
+     * @param content - Content of document
+     * @return CMSSignedData - Extended CMS signed data
+     * @throws NoSuchAlgorithmException - When algorithm is not supported 
+     * @author vakhtang koroghlishvili
+     */
+    private CMSSignedData extendSignedData(CMSSignedData signedData, InputStream content)
+            throws NoSuchAlgorithmException
     {
-        new RuntimeException("Document for signing does not exist");
-    }
 
-    // creating output document and prepare the IO streams.
-    String name = document.getName();
-    String substring = name.substring(0, name.lastIndexOf("."));
-    
-    File outputDocument = new File(document.getParent(), substring+"_signed.pdf");
-    FileInputStream fis = new FileInputStream(document);
-    FileOutputStream fos = new FileOutputStream(outputDocument);
+        SignerInformationStore signerInformationStore = signedData.getSignerInfos();
+        ArrayList<SignerInformation> signerInformationArray = new ArrayList<SignerInformation>();
 
-    int c;
-    while ((c = fis.read(buffer)) != -1)
-    {
-      fos.write(buffer, 0, c);
-    }
-    fis.close();
-    fis = new FileInputStream(outputDocument);
+        Object[] informations = signerInformationStore.getSigners().toArray();
 
-    // load document
-    PDDocument doc = PDDocument.load(document);
+        for (Object info : informations)
+        {
+            SignerInformation signerInformation = (SignerInformation) info;
 
-    // create signature dictionary
-    PDSignature signature = new PDSignature();
-    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
-    // subfilter for basic and PAdES Part 2 signatures
-    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
-    signature.setName("signer name");
-    signature.setLocation("signer location");
-    signature.setReason("reason for signature");
+            SignerInformation inf = reNewUnsignedAttributes(signedData, signerInformation, content);
 
-    // the signing date, needed for valid signature
-    signature.setSignDate(Calendar.getInstance());
+            if (inf == null)
+            {
+                signerInformationArray.add(signerInformation);
+            }
+            else
+            {
+                signerInformationArray.add(inf);
+            }
 
-    // register signature dictionary and sign interface
-    if (options==null)
-    {
-      doc.addSignature(signature, this);
-    } 
-    else 
-    {
-      doc.addSignature(signature, this, options);
+        }
+
+        SignerInformationStore newSignerStore = new SignerInformationStore(signerInformationArray);
+        return CMSSignedData.replaceSigners(signedData, newSignerStore);
+
     }
-    
-    // write incremental (only for signing purpose)
-    doc.saveIncremental(fis, fos);
 
-    return outputDocument;
-  }
+    /**
+     * We are extending CMS Signature
+     * 
+     * @param signedData - CMS signed data
+     * @param signerInformation - information about signer
+     * @param content - content of document
+     * @return  Information about SignerInformation
+     * 
+     * @author vakhtang koroghlishvili
+     */
+    protected SignerInformation reNewUnsignedAttributes(CMSSignedData signedData, SignerInformation signerInformation,
+            InputStream content)
+    {
 
-  /**
-   * <p>
-   * SignatureInterface implementation.
-   * </p>
-   * 
-   * <p>
-   * This method will be called from inside of the pdfbox and create the pkcs7
-   * signature. The given InputStream contains the bytes that are providen by
-   * the byte range.
-   * </p>
-   * 
-   * <p>
-   * This method is for internal use only.
-   * </p>
-   * 
-   * <p>
-   * Here the user should use his favorite cryptographic library and implement a
-   * pkcs7 signature creation.
-   * </p>
-   */
-  public byte[] sign(InputStream content) throws SignatureException,
-      IOException
-  {
-    CMSProcessableInputStream input = new CMSProcessableInputStream(content);
-    CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
-    // CertificateChain
-    List<Certificate> certList = Arrays.asList(cert);
+        AttributeTable unsignedTable = signerInformation.getUnsignedAttributes();
 
-    CertStore certStore = null;
-    try
-    {
-      certStore = CertStore.getInstance("Collection",
-          new CollectionCertStoreParameters(certList), provider);
-      gen.addSigner(privKey, (X509Certificate) certList.get(0),
-          CMSSignedGenerator.DIGEST_SHA256);
-      gen.addCertificatesAndCRLs(certStore);
-      CMSSignedData signedData = gen.generate(input, false, provider);
-      return signedData.getEncoded();
+        ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector();
+        if (unsignedTable != null)
+        {
+            asn1EncodableVector = signerInformation.getUnsignedAttributes().toASN1EncodableVector();
+        }
+
+        Attribute signatureTimeStamp;
+        try
+        {
+            signatureTimeStamp = this.tsaCreator.getTimeStampAttribute(
+                    PKCSObjectIdentifiers.id_aa_signatureTimeStampToken, signerInformation.getSignature(), content);
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            return null;
+        }
+        asn1EncodableVector.add(signatureTimeStamp);
+        Attributes atrs = new Attributes(asn1EncodableVector);
+        SignerInformation newSignerInformation = SignerInformation.replaceUnsignedAttributes(signerInformation,
+                new AttributeTable(atrs));
+        return newSignerInformation;
     }
-    catch (Exception e)
-    {
-      // should be handled
-      System.err.println("Error while creating pkcs7 signature.");
-      e.printStackTrace();
-    }
-    throw new RuntimeException("Problem while preparing signature");
-  }
 
-  public static void main(String[] args) throws KeyStoreException,
-      NoSuchAlgorithmException, CertificateException, FileNotFoundException,
-      IOException, COSVisitorException, SignatureException
-  {
-    if (args.length != 3)
+    public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+            FileNotFoundException, IOException, COSVisitorException, SignatureException, OperatorCreationException
     {
-      usage();
-      System.exit(1);
-    }
-    else
-    {
-      File ksFile = new File(args[0]);
-      KeyStore keystore = KeyStore.getInstance("PKCS12", provider);
-      char[] pin = args[1].toCharArray();
-      keystore.load(new FileInputStream(ksFile), pin);
+        if (args.length != 3)
+        {
+            usage();
+            System.exit(1);
+        }
+        else
+        {
+            File ksFile = new File(args[0]);
+            KeyStore keystore = KeyStore.getInstance("PKCS12", provider);
+            char[] pin = args[1].toCharArray();
+            keystore.load(new FileInputStream(ksFile), pin);
 
-      File document = new File(args[2]);
+            File document = new File(args[2]);
 
-      CreateSignature signing = new CreateSignature(keystore, pin.clone());
-      signing.signPDF(document);
+            CreateSignature signing = new CreateSignature(keystore, pin.clone());
+
+            String tsaUrl = "http://tsa.safecreative.org";
+            TSACreator tsaCreator = new TSACreator(tsaUrl, null, null, SHA_256_IDENTIFIER);
+
+            signing.signPDF(document, tsaCreator);
+        }
+
     }
 
-  }
-
-  /**
-   * This will print the usage for this program.
-   */
-  private static void usage()
-  {
-    System.err.println("Usage: java " + CreateSignature.class.getName()
-        + " <pkcs12-keystore-file> <pin> <input-pdf>");
-  }
+    /**
+     * This will print the usage for this program.
+     */
+    private static void usage()
+    {
+        System.err.println("Usage: java " + CreateSignature.class.getName()
+                + " <pkcs12-keystore-file> <pin> <input-pdf>");
+    }
 }
 
 /**
- * Wrap a InputStream into a CMSProcessable object for bouncy castle. It's an
- * alternative to the CMSProcessableByteArray.
+ * Wrap a InputStream into a CMSProcessable object for bouncy castle. It's an alternative to the
+ * CMSProcessableByteArray.
  * 
  * @author Thomas Chojecki
  * 
@@ -277,27 +384,27 @@
 class CMSProcessableInputStream implements CMSProcessable
 {
 
-  InputStream in;
+    InputStream in;
 
-  public CMSProcessableInputStream(InputStream is)
-  {
-    in = is;
-  }
+    public CMSProcessableInputStream(InputStream is)
+    {
+        in = is;
+    }
 
-  public Object getContent()
-  {
-    return null;
-  }
+    public Object getContent()
+    {
+        return null;
+    }
 
-  public void write(OutputStream out) throws IOException, CMSException
-  {
-    // read the content only one time
-    byte[] buffer = new byte[8 * 1024];
-    int read;
-    while ((read = in.read(buffer)) != -1)
+    public void write(OutputStream out) throws IOException, CMSException
     {
-      out.write(buffer, 0, read);
+        // read the content only one time
+        byte[] buffer = new byte[8 * 1024];
+        int read;
+        while ((read = in.read(buffer)) != -1)
+        {
+            out.write(buffer, 0, read);
+        }
+        in.close();
     }
-    in.close();
-  }
 }
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/TSACreator.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/TSACreator.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/TSACreator.java	(working copy)
@@ -0,0 +1,269 @@
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.pdfbox.io.IOUtils;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.cms.Attribute;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.DigestCalculatorProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.tsp.TSPException;
+import org.bouncycastle.tsp.TimeStampRequest;
+import org.bouncycastle.tsp.TimeStampRequestGenerator;
+import org.bouncycastle.tsp.TimeStampResponse;
+import org.bouncycastle.tsp.TimeStampToken;
+
+/**
+ * 
+ * @author Vakhtang koroghlishvili
+ *
+ */
+public class TSACreator
+{
+
+    private String hashIdentifier;
+    private URL url;
+    private String userName;
+    private String password;
+    private DigestCalculatorProvider digestCalculatorProvider;
+    private static final Logger LOG = Logger.getLogger(TSACreator.class.getName());
+    /**
+     * 
+     * @param url- the address of TSA
+     * @param tsaUsername- user name of TSA
+     * @param tsaPassword- password of TSA
+     * @param hashIdentifier - algorithm identifier
+     * @throws OperatorCreationException - when we can't build DigestCalcProvBuilder
+     * @throws MalformedURLException - when URL have some problem
+     */
+    public TSACreator(String url, String tsaUsername, String tsaPassword, String hashIdentifier)
+            throws OperatorCreationException, MalformedURLException
+    {
+
+        LOG.info("Initializing varaibles in TSA client constructor");
+        this.setHashIdentifier(hashIdentifier);
+        URL tsaURL = new URL(url);
+        this.setUrl(tsaURL);
+        this.setUserName(tsaUsername);
+        this.setPassword(tsaPassword);
+        JcaDigestCalculatorProviderBuilder digestCalcProvBuilder = new JcaDigestCalculatorProviderBuilder()
+                .setProvider("BC");
+        this.setDigestCalculatorProvider(digestCalcProvBuilder.build());
+    }
+
+    /**
+     * 
+     * @param oid- identifier of ASN1Object
+     * @param messageImprint- message imprint of document
+     * @param content- stream of content
+     * @return we return Attribute value
+     * @throws NoSuchAlgorithmException- when we can't
+     * work with your algorithm
+     */
+    public Attribute getTimeStampAttribute(ASN1ObjectIdentifier objectIdentifier, byte[] messageImprint,
+            InputStream content) throws NoSuchAlgorithmException
+    {
+
+        LOG.info("We are getting the time stamp attribute");
+        try
+        {
+            
+            MessageDigest msgDig = MessageDigest.getInstance(getHashIdentifier(), new BouncyCastleProvider());
+            byte[] digesttoTimeStamp = msgDig.digest(messageImprint);
+
+            byte[] tokenBytes = null;
+            try
+            {
+                tokenBytes = getTimeStampToken(digesttoTimeStamp);
+            }
+            catch (TSPException e)
+            {
+                LOG.log(Level.SEVERE, "can't get Time Stump Token", e);
+                throw new RuntimeException("can't get Time Stump Token");
+            }
+
+            Attribute signatureTimeStamp = new Attribute(objectIdentifier, new DERSet(
+                    TSAUtils.byteToASN1Objec(tokenBytes)));
+
+            return signatureTimeStamp;
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 
+     * @param imprint is the the array of bytes for the
+     * resulting hash value.
+     * @return encoded is time stamp Token
+     * @throws  IOException- if we can't get encoded request,
+     * or can't get TSA Request, or when we can't create
+     * TimeStumpResoponse
+     * @throws TSPException- When we can't create Time 
+     * StampResponse or when we can't validate response 
+     * - this happens when the request can not match
+     * this response.
+     */
+    public byte[] getTimeStampToken(byte[] imprint) throws IOException, TSPException
+    {
+        LOG.log(Level.INFO, "imprint value is:"+Arrays.toString(imprint));
+
+        LOG.log(Level.INFO, "we are getting time stamp token using imprint");
+        byte[] tsaResponse = null;
+
+        TimeStampRequestGenerator tsaGenerator = new TimeStampRequestGenerator();
+        tsaGenerator.setCertReq(true);
+
+        LOG.log(Level.INFO, "we are generating nonce value for more security");
+        BigInteger nonce = TSAUtils.generateNonce(0, 97359710);
+        LOG.log(Level.INFO, "nonce is"+nonce);
+
+        LOG.log(Level.INFO, "generate TSA request");
+        TimeStampRequest request = tsaGenerator.generate(new ASN1ObjectIdentifier(getHashIdentifier()), imprint, nonce);
+
+        byte[] requestData = request.getEncoded();
+        tsaResponse = getTSAResponse(requestData);
+
+        TimeStampResponse response = new TimeStampResponse(tsaResponse);
+        response.validate(request);
+
+        LOG.log(Level.INFO, "Successful validating");
+        
+        TimeStampToken tsToken = response.getTimeStampToken();
+        if (tsToken != null)
+        {
+            LOG.log(Level.INFO, "We have already Time Stamp token! \n \nnonce is:" +tsToken.getTimeStampInfo().getNonce() 
+                    + "\nAlgorithm identifier: "+tsToken.getTimeStampInfo().getHashAlgorithm().getAlgorithm().getId()
+                    + "\nGenerated Date:"+tsToken.getTimeStampInfo().getGenTime()
+                    + "\nimprint value:"+Arrays.toString(imprint) + "\n");
+       
+        }
+        else
+        {
+            LOG.log(Level.SEVERE, "OUR TSA token is NULL");
+            throw new RuntimeException("ERROR: OUR TSA token is NULL!");
+        }
+
+        byte[] encoded = tsToken.getEncoded();
+        return encoded;
+    }
+
+
+
+    /**
+     * 
+     * @param request - encoded TimeStampRequest data
+     * @return response bytes - just response data
+     * @throws IOException - when input stream of TSA have problems
+     */
+    private byte[] getTSAResponse(byte[] request) throws IOException
+    {
+
+        URLConnection tsaConnection = prepareTSAConnection();
+        OutputStream outputStreamData = tsaConnection.getOutputStream();
+        outputStreamData.write(request);
+        outputStreamData.close();
+        InputStream is = tsaConnection.getInputStream();
+        byte[] respBytes = IOUtils.toByteArray(is);
+
+        return respBytes;
+    }
+
+    /**
+     * Prepare TSAConnection - sets request properties
+     * 
+     * @return URLConnection - We return TSA URL connection
+     * @throws IOException- when we can't open TSA URL Connection
+     */
+    private URLConnection prepareTSAConnection() throws IOException
+    {
+
+        URLConnection tsaConn;
+        tsaConn = (URLConnection) getUrl().openConnection();
+        tsaConn.setUseCaches(true);
+        tsaConn.setAllowUserInteraction(true);
+        tsaConn.setDoOutput(true);
+        tsaConn.setDoInput(true);
+        tsaConn.setUseCaches(true);
+        tsaConn.setRequestProperty("Content-Transfer-Encoding", "binary");
+        tsaConn.setRequestProperty("Content-Type", "application/timestamp-query");
+
+        if (userName != null && password != null)
+        {
+            if (userName.length() != 0 && password.length() != 0)
+            {
+                tsaConn.setRequestProperty(userName, password);
+            }
+
+        }
+        return tsaConn;
+    }
+
+    public URL getUrl()
+    {
+        return url;
+    }
+
+    public void setUrl(URL url)
+    {
+        this.url = url;
+    }
+
+    public String getUserName()
+    {
+        return userName;
+    }
+
+    public void setUserName(String userName)
+    {
+        this.userName = userName;
+    }
+
+    public String getPassword()
+    {
+        return password;
+    }
+
+    public void setPassword(String password)
+    {
+        this.password = password;
+    }
+
+    public DigestCalculatorProvider getDigestCalculatorProvider()
+    {
+        return digestCalculatorProvider;
+    }
+
+    public void setDigestCalculatorProvider(DigestCalculatorProvider digestCalculatorProvider)
+    {
+        this.digestCalculatorProvider = digestCalculatorProvider;
+    }
+
+    public String getHashIdentifier()
+    {
+        return hashIdentifier;
+    }
+
+    public void setHashIdentifier(String hashIdentifier)
+    {
+        this.hashIdentifier = hashIdentifier;
+    }
+
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/TSAUtils.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/TSAUtils.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/TSAUtils.java	(working copy)
@@ -0,0 +1,67 @@
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Random;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * 
+ * @author vakhtang koroghlishvili
+ *
+ */
+public class TSAUtils
+{
+
+    /**
+     * 
+     * @param data - time stamp token byte
+     * @return ASN1Object which is created by the
+     * ASN1InputStream of the time stamp token
+     * @throws IOException - if we can't cast
+     * ASN1Primitive to ASN1Object
+     */
+    public static ASN1Object byteToASN1Objec(byte[] data) throws IOException
+    {
+        ASN1InputStream in = null;
+        try
+        {
+            in = new ASN1InputStream(data);
+            ASN1Primitive asn1Primitive = in.readObject();
+            return (ASN1Object) asn1Primitive;
+        }
+        catch (ClassCastException e)
+        {
+            throw new IOException("can't cast to the  ASN1Object object");
+        }
+
+    }
+    
+    /**
+     * Generates salt for more security. Is does not only get number 
+     * from the specified range-  from minimum value to maximum- there
+     * we use current time and etc.
+     * 
+     * @param min - minimum value is the additional value
+     * @param max - maximum value is the additional value
+     * @return
+     */
+    public static BigInteger generateNonce(int min, int max)
+    {
+
+        Random rand = new Random();
+
+        Integer randomNum = rand.nextInt((max - min) + 1) + min;
+
+        BigInteger nonce = new BigInteger(randomNum.toString());
+
+        Long timeLong = System.currentTimeMillis();
+        Integer timeInt = timeLong != null ? timeLong.intValue() : 761820123;
+
+        return nonce.multiply((new BigInteger(timeInt.toString())));
+    }
+
+}
