Hi,

Its a great guideline to include the TimeStamp while signing a pdf. But when
i am opening on different version of Adobe REader, its gving different
result. In Adobe v 8, its working fine but in Adobe v 7 its giving i guess
bad request. so, is there any Acrofield which governs the usage of PDF and
makes it compatible for all Adobe reader OR this implementation is
applicable to only Adobe v 8 and later version?

I have one more question, i am able to timestamp the signature successfully.
But only when i am creating a new PDF file. If i am using the same PDF file
name as a source and destination to make it as a certified, it gives
ClassCastException, ArrayIndexOutOfBoundsException as follows depending upon
the usage of sap.preClose(exc) method. 

When i am adding the contents using the following approach then it is giving
ClassCastException as follows:

Integer inte = new Integer(contentEst * 2 + 2);
HashMap exc = new HashMap();
exc.put(PdfName.CONTENTS, new
PdfString(inte.toString().getBytes()).setHexWriting(true));
sap.preClose(exc);

java.lang.ClassCastException
        at com.lowagie.text.pdf.PdfSignatureAppearance.preClose(Unknown
Source)
        at LunaSigner.signPDF(LunaSigner.java:307)
        at LunaSigner.main(LunaSigner.java:100)

When i am adding the contents using the following approach then it is giving
IllegalArgumentException as follows:

HashMap exc = new HashMap();
exc.put(PdfName.CONTENTS, inte);
sap.preClose(exc);

java.lang.IllegalArgumentException
        at java.nio.Buffer.position(Buffer.java:218)
        at com.lowagie.text.pdf.MappedRandomAccessFile.seek(Unknown Source)
        at com.lowagie.text.pdf.RandomAccessFileOrArray.seek(Unknown Source)
        at com.lowagie.text.pdf.PdfReader.getStreamBytesRaw(Unknown Source)
        at com.lowagie.text.pdf.PdfReader.getStreamBytesRaw(Unknown Source)
        at com.lowagie.text.pdf.PRStream.toPdf(Unknown Source)
        at com.lowagie.text.pdf.PdfIndirectObject.writeTo(Unknown Source)
        at com.lowagie.text.pdf.PdfWriter$PdfBody.add(Unknown Source)
        at com.lowagie.text.pdf.PdfWriter.addToBody(Unknown Source)
        at com.lowagie.text.pdf.PdfStamperImp.close(Unknown Source)
        at com.lowagie.text.pdf.PdfSignatureAppearance.preClose(Unknown
Source)
        at LunaSigner.signPDF(LunaSigner.java:307)
        at LunaSigner.main(LunaSigner.java:100)


So, if the source file and destination file is same, then the below
mentioned code is bouncing at sap.preClose(exc) step.

HashMap exc = new HashMap();
exc.put(PdfName.CONTENTS, inte);
sap.preClose(exc);

But the same code works fine if i am creating a new pdf and have source and
output pdf name different. so, please reply with you comments on the above
points.

Thanks
Gurpreet Singh


Martin Brunecky wrote:
> 
> Since iText currently lacks a direct support for time-stamped PDF
> signatures
> 
> 
> (signatures backed by a Time Stamp Authority - TSA), a fair amount of
> effort
> 
> 
> is needed to match the Acrobat and Reader functionality.
> 
> However, it can be done - at the cost of iText source (PdfPKCS7)
> augmentation.
> 
>  
> 
> The following posting is essentially a re-packaging of the original
> posting
> by
> 
>  
> 
>                 >>>>>> Aiken Sam, 2006-11-15 <<<<<<<<
> 
>      
> 
> Sam deserves all the credits for this functionality. My contribution is
> limited
> 
> to refactoring for subclassing, some minor fixes, cleanup and testing.
> 
>  
> 
> OBJECTIVE:
> 
> My posting is made out of self-interest: I would like to see the support
> for
> 
> time-stamped signing built into iText. Because class PdfPKCS7 was not
> meant
> 
> for subclassing, any "outside iText" implementation ends up cloning most
> 
> of that class - even though changes required for time-stamping are small.
> 
>  
> 
> My re-packaging of Aiken Sam's work aimed at two main goals:
> 
> - embed the support within iText with minimal changes to the existing code
> 
> - allow subclassing the TSA client for specific RFC 3161 timestamp
> providers
> 
>   (such as using provider supplied toolkit) and communication protocols.
> 
>  
> 
> TESTING:
> 
> I have done testing using several flavors of certificate (PKCS12 based
> certs,
> 
> PKCS11 USB token from VeriSign CDS for Adobe).
> 
> I tested using TSA at "http://dse200.ncipher.com/TSS/HttpTspServer"; (no
> account
> 
> or password needed) and TSA at www.digistamp.com, offering 'test' service
> for free.
> 
> Other services used by Aiken Sam in his testing are now off-the-air.
> 
> I also tested with other Bouncy Castle releases (bc*-jdk15-137.jar).
> 
>  
> 
> DEPENDENCIES:
> 
> The class TSAClientBouncyCastle adds a new iText build dependency, Bouncy
> Castle
> 
> time stamp support: bctsp-jdk14-135.jar (you must add this to
> src/ant/compile.xml).
> 
> You can find this jar on sourceforge, or at www.bouncycastle.org.
> 
>  
> 
>  
> 
> DEMO:
> 
> Included (below) is a 'demo' sample generating an invisible, time-stamped
> 
> signature, with its support classes. All code builds with javac
> -source=1.4,
> 
> even though I prefer 1.5.
> 
>  
> 
> LIMITATIONS:
> 
> The implementation and demo provided here uses explicit calls to
> preClose()
> and
> 
> PdfPKCS7.getEncodedPKCS7(). 
> 
> It would be possible to 'hide' all of this by adding something like 
> 
> sap.setTSAClient(client) together with adding time-stamp handling to
> preClose()
> 
> and close() methods -- I considered such changes too intrusive at this
> point.
> 
>  
> 
> ISSUES:
> 
> The main issue is what exactly Adobe considers a valid timestamp. The RFC
> 3161
> 
> leaves the time stamped "imprint" open to the protocol users (only
> asserting
> the
> 
> TSA must NOT change it), and hence it is upon the application to define
> it.
> 
> When Adobe reader encounters some 'other' time-stamped imprint, it ignores
> it.
> 
> I would appreciate any pointers to Adobe specs, as I would like to expand
> upon
> 
> the current work - in some cases, my control over the 'imprint' generation
> 
> is limited.
> 
>  
> 
>  
> 
>  
> 
> ===== iText SOURCE CHANGES
> =====================================================
> 
> Source changes comprise of changes to PdfPKCS7 (3 areas), one new
> interface
> 
> and one new class ("default" TSA caller implementation).
> 
>  
> 
> ===== PdfPKCS7.java
> ============================================================
> 
> The following is a diff output showing changes from iText 2.0.4 source.
> Changes
> 
> include one signature change (getEncodedPKCS7), adding
> backwards-compatible
> ones,
> 
> TSA client calling code, and one new method -
> buildUnauthenticatedAttributes().
> 
>  
> 
>>diff -b  PdfPKCS7.orig PdfPKCS7.java
> 
> 770c770
> 
> <         return getEncodedPKCS7(null, null);
> 
> ---
> 
>>         return getEncodedPKCS7(null, null, null);
> 
> 780a781,793
> 
>>         return getEncodedPKCS7(secondDigest, signingTime, null);
> 
>>     }
> 
>> 
> 
>>     /**
> 
>>      * Gets the bytes for the PKCS7SignedData object. Optionally the
> authenticatedAttributes
> 
>>      * in the signerInfo can also be set, OR a time-stamp-authority
>> client
> 
>>      * may be provided.
> 
>>      * @param secondDigest the digest in the authenticatedAttributes
> 
>>      * @param signingTime the signing time in the authenticatedAttributes
> 
>>      * @param tsaClient TSAClient - null or an optional time stamp
> authority client
> 
>>      * @return byte[] the bytes for the PKCS7SignedData object
> 
>>      */
> 
>>     public byte[] getEncodedPKCS7(byte secondDigest[], Calendar
> signingTime, TSAClient tsaClient) {
> 
> 881a895,907
> 
>>             // When requested, go get and add the timestamp. May throw an
> exception.
> 
>>             // Added by Martin Brunecky, 07/12/2007 folowing Aiken Sam,
> 2006-11-15
> 
>>             // Sam found Adobe expects time-stamped SHA1-1 of the
> encrypted digest
> 
>>             if (tsaClient != null) {
> 
>>                 byte[] tsImprint =
> MessageDigest.getInstance("SHA-1").digest(digest);
> 
>>                 byte[] tsToken = tsaClient.getTimeStampToken(this,
> tsImprint);
> 
>>                 if (tsToken != null) {
> 
>>                     ASN1EncodableVector unauthAttributes =
> buildUnauthenticatedAttributes(tsToken);
> 
>>                     if (unauthAttributes != null) {
> 
>>                         signerinfo.add(new DERTaggedObject(false, 1, new
> DERSet(unauthAttributes)));
> 
>>                     }
> 
>>                 }
> 
>>             }
> 
> 922a949,976
> 
>>     /**
> 
>>      * Added by Aiken Sam, 2006-11-15, modifed by Martin Brunecky
> 07/12/2007
> 
>>      * to start with the timeStampToken (signedData
>> 1.2.840.113549.1.7.2).
> 
>>      * Token is the TSA response without response status, which is
>> usually
> 
>>      * handled by the (vendor supplied) TSA request/response interface).
> 
>>      * @param timeStampToken byte[] - time stamp token, DER encoded
> signedData
> 
>>      * @return ASN1EncodableVector
> 
>>      * @throws IOException
> 
>>      */
> 
>>     private ASN1EncodableVector buildUnauthenticatedAttributes(byte[]
> timeStampToken)  throws IOException {
> 
>>         if (timeStampToken == null)
> 
>>             return null;
> 
>> 
> 
>>         // @todo: move this together with the rest of the defintions
> 
>>         String ID_TIME_STAMP_TOKEN = "1.2.840.113549.1.9.16.2.14"; // RFC
> 3161 id-aa-timeStampToken
> 
>> 
> 
>>          ASN1InputStream tempstream = new ASN1InputStream(new
> ByteArrayInputStream(timeStampToken));
> 
>>          ASN1EncodableVector unauthAttributes = new
>> ASN1EncodableVector();
> 
>> 
> 
>>          ASN1EncodableVector v = new ASN1EncodableVector();
> 
>>          v.add(new DERObjectIdentifier(ID_TIME_STAMP_TOKEN)); //
> id-aa-timeStampToken
> 
>>          ASN1Sequence seq = (ASN1Sequence) tempstream.readObject();
> 
>>          v.add(new DERSet(seq));
> 
>> 
> 
>>          unauthAttributes.add(new DERSequence(v));
> 
>>          return unauthAttributes;
> 
>>      }
> 
>> 
> 
>  
> 
> ===== TSAClient.java
> =u=========================================================
> 
> package com.lowagie.text.pdf;
> 
>  
> 
> /**
> 
>  * Time Stamp Authority client (caller) interface.
> 
>  * <p>
> 
>  * Interface used by the PdfPKCS7 digital signature builder to call
> 
>  * Time Stamp Authority providing RFC 3161 compliant time stamp token.
> 
>  * @author Martin Brunecky, 07/17/2007
> 
> */
> 
> public interface TSAClient {
> 
>    /**
> 
>      * Get the time stamp token size estimate.
> 
>      * Implementation must return value large enough to accomodate the
> entire token
> 
>      * returned by getTimeStampToken() _prior_ to actual
> getTimeStampToken()
> call.
> 
>      */
> 
>     public int getTokenSizeEstimate();
> 
>  
> 
>     /**
> 
>      * Get RFC 3161 timeStampToken.
> 
>      * Method may return null indicating that timestamp should be skipped.
> 
>      * @param caller PdfPKCS7 - calling PdfPKCS7 instance (in case caller
> needs it)
> 
>      * @param imprint byte[] - data imprint to be time-stamped
> 
>      * @return byte[] - encoded, TSA signed data of the timeStampToken
> 
>      * @throws Exception - TSA request failed
> 
>      */
> 
>     public byte[] getTimeStampToken(PdfPKCS7 caller, byte[] imprint)
> throws
> Exception;
> 
>  
> 
> }
> 
>  
> 
>  
> 
> ===== TSAClientBouncyCastle.java
> ===============================================
> 
> package com.lowagie.text.pdf;
> 
>  
> 
> import java.io.*;
> 
> import java.math.*;
> 
> import java.net.*;
> 
>  
> 
>  
> 
> import org.bouncycastle.asn1.cmp.*;
> 
> import org.bouncycastle.asn1.x509.*;
> 
> import org.bouncycastle.tsp.*;
> 
>  
> 
> /**
> 
>  * Time Stamp Authority Client interface implementation using Bouncy
> Castle
> 
>  * org.bouncycastle.tsp package.
> 
>  * <p>
> 
>  * Created by Aiken Sam, 2006-11-15, refactored by Martin Brunecky,
> 07/15/2007
> 
>  * for ease of subclassing.
> 
>  * </p>
> 
>  */
> 
> public class TSAClientBouncyCastle implements TSAClient {
> 
>     protected String tsaURL;
> 
>     protected String tsaUsername;
> 
>     protected String tsaPassword;
> 
>     protected int    tokSzEstimate;
> 
>  
> 
>     public TSAClientBouncyCastle(String url) {
> 
>         this(url, null, null, 4096);
> 
>     }
> 
>  
> 
>     public TSAClientBouncyCastle(String url, String username, String
> password) {
> 
>         this(url, username, password, 4096);
> 
>     }
> 
>  
> 
>     /**
> 
>      * Constructor.
> 
>      * Note the token size estimate is updated by each call, as the token
> 
>      * size is not likely to change (as long as we call the same TSA using
> 
>      * the same imprint length).
> 
>      * @param url String - Time Stamp Authority URL (i.e.
> "http://tsatest1.digistamp.com/TSA";)
> 
>      * @param username String - user(account) name
> 
>      * @param password String - password
> 
>      * @param tokSzEstimate int - estimated size of received time stamp
> token (DER encoded)
> 
>      */
> 
>     public TSAClientBouncyCastle(String url, String username, String
> password, int tokSzEstimate) {
> 
>         this.tsaURL       = url;
> 
>         this.tsaUsername  = username;
> 
>         this.tsaPassword  = password;
> 
>         this.tokSzEstimate = tokSzEstimate;
> 
>     }
> 
>  
> 
>     /**
> 
>      * Get the token size estimate.
> 
>      * Returned value reflects the result of the last succesfull call,
> padded
> 
>      * @return int
> 
>      */
> 
>     public int getTokenSizeEstimate() {
> 
>         return tokSzEstimate;
> 
>     }
> 
>  
> 
>     public byte[] getTimeStampToken(PdfPKCS7 caller, byte[] imprint)
> throws
> Exception {
> 
>         return getTimeStampToken(imprint);
> 
>     }
> 
>  
> 
>     /**
> 
>      * Get timestamp token - Bouncy Castle request encoding / decoding
> layer
> 
>      */
> 
>     protected byte[] getTimeStampToken(byte[] imprint) throws Exception {
> 
>        byte[] respBytes = null;
> 
>        try {
> 
>            // Setup the time stamp request
> 
>            TimeStampRequestGenerator tsqGenerator = new
> TimeStampRequestGenerator();
> 
>            tsqGenerator.setCertReq(true);
> 
>            // tsqGenerator.setReqPolicy("1.3.6.1.4.1.601.10.3.1");
> 
>            BigInteger nonce =
> BigInteger.valueOf(System.currentTimeMillis());
> 
>            TimeStampRequest request =
> tsqGenerator.generate(X509ObjectIdentifiers.id_SHA1.getId() , imprint,
> nonce);
> 
>            byte[] requestBytes = request.getEncoded();
> 
>  
> 
>            // Call the communications layer
> 
>            respBytes = getTSAResponse(requestBytes);
> 
>  
> 
>            // Handle the TSA response
> 
>            TimeStampResponse response = new TimeStampResponse(respBytes);
> 
>  
> 
>            // validate communication level attributes (RFC 3161 PKIStatus)
> 
>            response.validate(request);
> 
>            PKIFailureInfo failure = response.getFailInfo();
> 
>            int value = (failure == null) ? 0 : failure.intValue();
> 
>            if (value != 0) {
> 
>                // @todo: Translate value of 15 error codes defined by
> PKIFailureInfo to string
> 
>                throw new Exception("Invalid TSA '" + tsaURL + "' response,
> code " + value);
> 
>            }
> 
>            // @todo: validate the time stap certificate chain (if we want
> 
>            //        assure we do not sign using an invalid timestamp).
> 
>  
> 
>            // extract just the time stamp token (removes communication
> status info)
> 
>            TimeStampToken  tsToken = response.getTimeStampToken();
> 
>            if (tsToken == null) {
> 
>                throw new Exception("TSA '" + tsaURL + "' failed to return
> time stamp token");
> 
>            }
> 
>            TimeStampTokenInfo info = tsToken.getTimeStampInfo(); // to
> view
> details
> 
>            byte[] encoded = tsToken.getEncoded();
> 
>            long stop = System.currentTimeMillis();
> 
>  
> 
>            // Update our token size estimate for the next call (padded to
> be
> safe)
> 
>            this.tokSzEstimate = encoded.length + 32;
> 
>            return encoded;
> 
>        }
> 
>        catch (Exception e) {
> 
>            throw e;
> 
>        }
> 
>        catch (Throwable t) {
> 
>            throw new Exception("Failed to get TSA response from '" +
> tsaURL
> +"'", t);
> 
>        }
> 
>     }
> 
>  
> 
>    /**
> 
>     * Get timestamp token - communications layer
> 
>     * @return - byte[] - TSA response, raw bytes (RFC 3161 encoded)
> 
>     */
> 
>    protected byte[] getTSAResponse(byte[] requestBytes) throws Exception {
> 
>         // Setup the TSA connection
> 
>         URL url = new URL(tsaURL);
> 
>         URLConnection tsaConnection = (URLConnection)
> url.openConnection();
> 
>  
> 
>         tsaConnection.setDoInput(true);
> 
>         tsaConnection.setDoOutput(true);
> 
>         tsaConnection.setUseCaches(false);
> 
>         tsaConnection.setRequestProperty("Content-Type",
> "application/timestamp-query");
> 
>         //tsaConnection.setRequestProperty("Content-Transfer-Encoding",
> "base64");
> 
>         tsaConnection.setRequestProperty("Content-Transfer-Encoding",
> "binary");
> 
>  
> 
>         if ((tsaUsername != null) && !tsaUsername.equals("") ) {
> 
>             String userPassword = tsaUsername + ":" + tsaPassword;
> 
>             tsaConnection.setRequestProperty("Authorization", "Basic " +
> 
>                 new String(new
> sun.misc.BASE64Encoder().encode(userPassword.getBytes())));
> 
>         };
> 
>         OutputStream out = tsaConnection.getOutputStream();
> 
>         out.write(requestBytes);
> 
>         out.close();
> 
>  
> 
>         // Get TSA response as a byte array
> 
>         InputStream inp = tsaConnection.getInputStream();
> 
>         ByteArrayOutputStream baos = new ByteArrayOutputStream();
> 
>         byte[] buffer = new byte[1024];
> 
>         int bytesRead = 0;
> 
>         while ((bytesRead = inp.read(buffer, 0, buffer.length)) >= 0) {
> 
>             baos.write(buffer, 0, bytesRead);
> 
>         }
> 
>         byte[] respBytes = baos.toByteArray();
> 
>  
> 
>         String encoding = tsaConnection.getContentEncoding();
> 
>         if (encoding != null && encoding.equalsIgnoreCase("base64")) {
> 
>             sun.misc.BASE64Decoder dec = new sun.misc.BASE64Decoder();
> 
>             respBytes = dec.decodeBuffer(new String(respBytes));
> 
>         }
> 
>         return respBytes;
> 
>     }
> 
>  
> 
> }
> 
>  
> 
>  
> 
> ===== D E M O
> ==================================================================
> 
> To use the following demo, you must have a PKCS12 certificate, such as
> VeriSign
> 
> digital mail ID (or refer to my PKCS11 posting for PKCS11, JCS cert
> support),
> 
> and you need access to some Time Stamp Authority (TSA) service, such as an
> 
> account with www.digistamp.com (free test service available).
> 
>  
> 
> Depending upon certicate(s) used, you may have to adjust trusted
> certificates
> 
> in your Adobe Acrobat or reader.
> 
>  
> 
> ===== PdfSignerDemo.java
> =======================================================
> 
>  
> 
> package demo;
> 
>  
> 
> import java.io.*;
> 
> import java.util.*;
> 
>  
> 
> import com.lowagie.text.*;
> 
> import com.lowagie.text.pdf.*;
> 
>  
> 
> /**
> 
>  * Demo using iText to digitally sign PDF document with a valid time-stamp
> 
>  * Demo dependecies:
> 
>  * SignerKeystore - interface providing signing certificate access
> 
>  * SignerKeystorePKCS12 - implemnation importing PKCS12 (.pfx) certificate
> 
>  */
> 
> public class PdfSignerDemo {
> 
>     private SignerKeystore sks;
> 
>     private TSAClient def;
> 
>  
> 
>     public PdfSignerDemo(SignerKeystore sks, TSAClient tsc) throws
> Exception
> {
> 
>         this.sks = sks;
> 
>         this.def = tsc;
> 
>     }
> 
>  
> 
>     public void signPDF(String srcFile, String dstFile) throws Exception {
> 
>         signPDF(srcFile, dstFile, def);
> 
>     }
> 
>  
> 
>     public void signPDF(String srcFile, String dstFile, TSAClient tsc) {
> 
>         try {
> 
>             // Prepare for PDF file handling (copy, stamp)
> 
>             PdfReader reader = new PdfReader(srcFile);
> 
>             FileOutputStream fout = new FileOutputStream(dstFile);
> 
>             PdfStamper stp = PdfStamper.createSignature(reader, fout,
> '\0');
> 
>             PdfSignatureAppearance sap = stp.getSignatureAppearance();
> 
>             setAppearance(sap);
> 
>  
> 
>             // Configure PDF signature dictionary (PdfName.ADOBE_PPKLITE
> works too)
> 
>             PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKMS,
> 
>                                                 PdfName.ADBE_PKCS7_SHA1);
> 
>             // dic.setName (null); // optional - PdfPKCS7 uses the
> certificate CN
> 
>             dic.setReason(sap.getReason());
> 
>             dic.setLocation(sap.getLocation());
> 
>             dic.setContact(sap.getContact());
> 
>             dic.setDate(new PdfDate(sap.getSignDate())); // time-stamp
> will
> over-rule this
> 
>             sap.setCryptoDictionary(dic);
> 
>  
> 
>             // Estimate signature size, creating a 'fake' one using fake
> data
> 
>             // (SHA1 length does not depend upon the data length)
> 
>             byte[] estSignature = genPKCS7Signature(new
> ByteArrayInputStream("fake".getBytes()), null);
> 
>             int contentEst = estSignature.length +
> 
>                              ((tsc == null) ? 0 :
> tsc.getTokenSizeEstimate());
> 
>  
> 
>             // Preallocate excluded byte-range for the signature content
> (hex encoded)
> 
>             HashMap exc = new HashMap();
> 
>             exc.put(PdfName.CONTENTS, new Integer(contentEst * 2 + 2));
> 
>             sap.preClose(exc);
> 
>  
> 
>             // Get the true data signature, including a true time stamp
> token
> 
>             byte[] encodedSig = genPKCS7Signature(sap.getRangeStream(),
> tsc);
> 
>             if (contentEst + 2 < encodedSig.length) {
> 
>                 throw new Exception("Timestamp size estimate " +
> contentEst
> +
> 
>                                     " is too low for actual " +
> 
>                                     encodedSig.length);
> 
>             }
> 
>  
> 
>             // Copy signature into a zero-filled array, padding it up to
> estimate
> 
>             byte[] paddedSig = new byte[contentEst];
> 
>             System.arraycopy(encodedSig, 0, paddedSig, 0,
> encodedSig.length);
> 
>  
> 
>             // Finally, load zero-padded signature into the signature
> field
> /Content
> 
>             PdfDictionary dic2 = new PdfDictionary();
> 
>             dic2.put(PdfName.CONTENTS, new
> PdfString(paddedSig).setHexWriting(true));
> 
>             sap.close(dic2); // closes sap.close()
> 
>         } catch (Throwable t) {
> 
>             System.out.println("Signing failed" + t);
> 
>             t.printStackTrace();
> 
>         }
> 
>     }
> 
>  
> 
>  
> 
>     /**
> 
>      * Setup signature appearance. Override to define specifics.
> 
>      * @param sap PdfSignatureAppearance
> 
>      */
> 
>     protected void setAppearance(PdfSignatureAppearance sap) {
> 
>         // Make this an invisible signature
> 
>         sap.setVisibleSignature(new Rectangle(0, 0, 0, 0), 1,
> "Signature");
> // empty makes field invisible
> 
>     }
> 
>  
> 
>  
> 
>     /**
> 
>      * Generate the PKCS7 encoded signature
> 
>      * @param data InputStream - data to digest
> 
>      * @param doTimestamp boolean - true to include time-stamp
> 
>      * @return byte[]
> 
>      * @throws Exception
> 
>      */
> 
>     protected byte[] genPKCS7Signature(InputStream data, TSAClient tsc)
> throws  Exception {
> 
>         // assume sub-filter is adobe.pkcs7.sha1
> 
>         PdfPKCS7 sgn = new PdfPKCS7(sks.getPrivateKey(), sks.getChain(),
> null,
> 
>                                     "SHA1", sks.getProvider().getName(),
> true);
> 
>         byte[] buff = new byte[2048];
> 
>         int len = 0;
> 
>         while ((len = data.read(buff)) > 0) {
> 
>             sgn.update(buff, 0, len);
> 
>         }
> 
>         return sgn.getEncodedPKCS7(null, null, tsc);
> 
>     }
> 
>  
> 
>     // Configuration
> 
>     // MY digital certificate (PKCS#12 - get an e-mail digital ID from
> VeriSign)
> 
>     private static final String CERT_PATH  = "mycert.pfx";
> 
>     private static final String CERT_PASSW = "mypassword";
> 
>  
> 
>     // MY TSA account (go to www.digistamp.com and create one - test is
> free)
> 
>     private static final String TSA_URL    =
> "http://tsatest1.digistamp.com/TSA"; ;
> 
>     private static final String TSA_ACCNT  = "99999";
> 
>     private static final String TSA_PASSW  = "pwdpwd";
> 
>  
> 
>     public static void main(String[] args) throws Exception {
> 
>         if (args.length < 1) {
> 
>             System.out.println("Usage: PdfSignerDemo file {file}
> {file}...");
> 
>             System.exit(1);
> 
>         }
> 
>         SignerKeystore sks = new SignerKeystorePKCS12(new
> FileInputStream(CERT_PATH), CERT_PASSW);
> 
>         TSAClient      tsc = new TSAClientBouncyCastle(TSA_URL, TSA_ACCNT,
> TSA_PASSW);
> 
>  
> 
>         PdfSignerDemo  demo = new PdfSignerDemo(sks, tsc);
> 
>         for (int i=0; i<args.length; i++) {
> 
>             int iDot = args[i].lastIndexOf('.');
> 
>             demo.signPDF(args[i], args[i].substring(0, iDot) + "_signed" +
> args[i].substring(iDot));
> 
>         }
> 
>     }
> 
> }
> 
>  
> 
> ===== SignerKeystore.java
> ======================================================
> 
> package demo;
> 
>  
> 
> import java.security.Provider;
> 
> import java.security.PrivateKey;
> 
> import java.security.cert.Certificate;
> 
>  
> 
> public interface SignerKeystore {
> 
>      public PrivateKey getPrivateKey() ;
> 
>      public Certificate[] getChain() ;
> 
>      public Provider getProvider();
> 
> }
> 
>  
> 
>  
> 
> ===== SignerKeystorePKCS12.java
> ================================================
> 
> package demo;
> 
>  
> 
> import java.io.*;
> 
> import java.security.*;
> 
> import java.security.cert.Certificate;
> 
>  
> 
> /**
> 
>  * SignerKeystore implementation using PKCS#12 file (.pfx etc)
> 
>  */
> 
> public class SignerKeystorePKCS12 implements SignerKeystore {
> 
>     private static Provider prov = null;
> 
>     private KeyStore ks;
> 
>     private String alias;
> 
>     private String pwd;
> 
>  
> 
>     private PrivateKey key;
> 
>     private Certificate[] chain;
> 
>  
> 
>     public SignerKeystorePKCS12(InputStream inp, String passw) throws
> Exception {
> 
>         // This should be done once only for the provider...
> 
>         if (prov == null) {
> 
>             prov = new
> org.bouncycastle.jce.provider.BouncyCastleProvider();
> 
>             Security.addProvider(prov);
> 
>         }
> 
>  
> 
>         this.ks = KeyStore.getInstance("pkcs12", prov);
> 
>         this.pwd = passw;
> 
>         this.ks.load(inp, pwd.toCharArray());
> 
>         this.alias = (String)ks.aliases().nextElement();
> 
>         this.key   = (PrivateKey)ks.getKey(alias, pwd.toCharArray());
> 
>         this.chain = ks.getCertificateChain(alias);
> 
>     }
> 
>  
> 
>     public PrivateKey getPrivateKey() {
> 
>         return key;
> 
>     }
> 
>  
> 
>     public Certificate[] getChain() {
> 
>         return chain;
> 
>     }
> 
>  
> 
>     public Provider getProvider() {
> 
>         return ks.getProvider();
> 
>     }
> 
> }
> 
>  
> 
> ===== E N D
> ===================================================================
> 
>  
> 
>  
> 
>  
> 
> 
> 
> 
> 
> Martin Brunecky
> Software Architect 
> 
> RecordFusion 
> 
> 
>  <mailto:[EMAIL PROTECTED]> [EMAIL PROTECTED]
> AIM: mbrunecky 
> 
> 
> tel: 
> fax: 
> 
>  
> <http://www.plaxo.com/click_to_call?src=jj_signature&To=303-865-8847+x+225&E
> [EMAIL PROTECTED]> 303-865-8847 x 225 
> 303-865-8846 
> 
>  
> 
> 
> 
>  <https://www.plaxo.com/add_me?u=38655967504&v0=2505222&k0=891308811> Add
> me
> to your address book...
> 
>  <http://www.plaxo.com/signature> Want a signature like this?
> 
>  
> 
> 
>  
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Splunk Inc.
> Still grepping through log files to find problems?  Stop.
> Now Search log events and configuration files using AJAX and a browser.
> Download your FREE copy of Splunk now >>  http://get.splunk.com/
> _______________________________________________
> iText-questions mailing list
> iText-questions@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/itext-questions
> Buy the iText book: http://itext.ugent.be/itext-in-action/
> 
> 

-- 
View this message in context: 
http://www.nabble.com/PDF-Digital-signature-with-timestamp---using-Time-Stamp-Authority---example-tf4147508.html#a12416847
Sent from the iText - General mailing list archive at Nabble.com.


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
iText-questions mailing list
iText-questions@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/itext-questions
Buy the iText book: http://itext.ugent.be/itext-in-action/

Reply via email to