By Date: <-- -->
By Thread: <-- -->

Signature timestamp



Here is my code, to get it running you have to download:
bouncycastle
commons-httpclient
commons-logging
commons-codec


import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.math.BigInteger; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Security; import java.security.cert.CertStore; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DEREncodableVector;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.SignerId;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.tsp.TSPAlgorithms;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;

import com.lowagie.text.pdf.PdfDictionary;
import com.lowagie.text.pdf.PdfName;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfSignatureAppearance;
import com.lowagie.text.pdf.PdfStamper;
import com.lowagie.text.pdf.PdfString;

public class Signer {

   /**
    *  (at) param args
    *  (at) throws Exception
    */
   public static void main(String[] args) throws Exception {
       PdfReader reader = new PdfReader("test.pdf");
       FileOutputStream fout = new FileOutputStream("test_signed.pdf");

       final int SIZE = 16000;

       PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
       PdfSignatureAppearance sap = stp.getSignatureAppearance();

       PdfDictionary dic = new PdfDictionary();
       dic.put(PdfName.TYPE, PdfName.SIG);
       dic.put(PdfName.FILTER, new PdfName("Adobe.PPKMS"));
       dic.put(PdfName.SUBFILTER, new PdfName("adbe.pkcs7.detached"));

       sap.setCryptoDictionary(dic);
       HashMap exc = new HashMap();
       exc.put(PdfName.CONTENTS, new Integer(SIZE));
       sap.preClose(exc);

       byte[] data = streamToByteArray(sap.getRangeStream());

// get signed data
byte[] ssig = sign(data);
// ////////////////////////


       byte[] outc = new byte[(SIZE - 2) / 2];
       System.arraycopy(ssig, 0, outc, 0, ssig.length);
       PdfDictionary dic2 = new PdfDictionary();

       dic2.put(PdfName.CONTENTS, new PdfString(outc).setHexWriting(true));
       sap.close(dic2);

   }

private static byte[] streamToByteArray(InputStream stream) throws Exception {
if (stream == null) {
return null;
} else {
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
byte buffer[] = new byte[1024];
int c = 0;
while ((c = stream.read(buffer)) > 0) {
byteArray.write(buffer, 0, c);
}
byteArray.flush();
return byteArray.toByteArray();
}
}
private static byte[] sign(byte[] data) {
byte[] res = null;


       Security.addProvider(new BouncyCastleProvider());

// ---- in real implementation, provide some SECURE way to get keystore
// ---- password from user! -------
String password = "12345"; // keystore password
String pfxFileName = "my.pfx";


       KeyStore ks = null;
       PublicKey pub = null;
       PrivateKey priv = null;
       java.security.cert.Certificate storecert = null;
       java.security.cert.Certificate[] certChain = null;
       ArrayList certList = new ArrayList();
       CertStore certs = null;

try {
ks = KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream(pfxFileName), password.toCharArray());
String ALIAS = (String) ks.aliases().nextElement();


           certChain = ks.getCertificateChain(ALIAS);
           for (int i = 0; i < certChain.length; i++)
               certList.add(certChain[i]);
           certs = CertStore.getInstance("Collection",
                   new CollectionCertStoreParameters(certList), "BC");

           priv = (PrivateKey) (ks.getKey(ALIAS, password.toCharArray()));

           storecert = ks.getCertificate(ALIAS);
           pub = ks.getCertificate(ALIAS).getPublicKey();
       } catch (Exception exc) {
           System.out.println("Problem with keystore access: "
                   + exc.toString());
           return null;
       }

       //System.out.println("Public Key Format: " + pub.getFormat());
       //System.out.println("Certificate " + storecert.toString());


byte[] contentbytes = data;

       try {
           CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();

signGen.addSigner(priv, (X509Certificate) storecert, CMSSignedDataGenerator.DIGEST_SHA1);
signGen.addCertificatesAndCRLs(certs);
CMSProcessable content = new CMSProcessableByteArray(contentbytes);


//generate signed data
CMSSignedData signedData = signGen.generate(content, "BC");
//add timestamp to signed data
signedData = addTimestamp(signedData);
byte[] signeddata = signedData.getEncoded();
System.out.println("Created signed message: " + signeddata.length
+ " bytes");


           res = signeddata;
       } catch (Exception ex) {
           System.out.println("Couldn't generate CMS signed message\n"
                   + ex.toString());
       }
       return res;
   }

/**
* Modyfy PKCS#7 data by adding timestamp
*
* (at) param signedData
* (at) throws Exception
*/
private static CMSSignedData addTimestamp(CMSSignedData signedData) throws Exception {
Collection ss = signedData.getSignerInfos().getSigners();
SignerInformation si = (SignerInformation) ss.iterator().next();
TimeStampToken tok = getTimeStampToken(1);


ASN1InputStream asn1InputStream = new ASN1InputStream (tok.getEncoded());
DERObject tstDER = asn1InputStream.readObject();
DERSet ds = new DERSet(tstDER);
Attribute a = new Attribute(new DERObjectIdentifier("1.2.840.113549.1.9.16.2.14"), ds);
DEREncodableVector dv = new DEREncodableVector();
dv.add(a);
AttributeTable at = new AttributeTable(dv);
si = SignerInformation.replaceUnsignedAttributes(si, at);
ss.clear();
ss.add(si);
SignerInformationStore sis = new SignerInformationStore(ss);
signedData = CMSSignedData.replaceSigners(signedData, sis);
return signedData;
}


private static TimeStampToken getTimeStampToken(int TSA) throws Exception {
Security.addProvider (new org.bouncycastle.jce.provider.BouncyCastleProvider());


PostMethod post = null;
switch (TSA) {
case 1:
post = new PostMethod("http://www.edelweb.fr/cgi-bin/service-tsp";);
break;


       case 2:
           post = new PostMethod("http://tsp.iaik.at/tsp/TspRequest";);
           break;

case 3:
post = new PostMethod("http://ns.szikszi.hu:8080/tsa";);
break;
case 4:
post = new PostMethod("http://time.certum.pl/";);
break;
}


TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
//request TSA to return certificate
reqGen.setCertReq (false);
//make a TSP request this is a dummy sha1 hash (20 zero bytes) and nonce=100
TimeStampRequest request =
reqGen.generate(TSPAlgorithms.SHA1,
new byte[20], BigInteger.valueOf(100));


byte[] enc_req = request.getEncoded();
ByteArrayInputStream bais = new ByteArrayInputStream(enc_req);
post.setRequestBody(bais);
post.setRequestContentLength (enc_req.length);
post.setRequestHeader("Content-type","application/timestamp-query");


       HttpClient http_client = new HttpClient();
       http_client.executeMethod(post);
       InputStream in = post.getResponseBodyAsStream();

//read TSP response
TimeStampResponse resp = new TimeStampResponse (in);
resp.validate (request);
System.out.println ("Timestamp validated");


       TimeStampToken  tsToken = resp.getTimeStampToken();
       SignerId signer_id = tsToken.getSID();

       BigInteger cert_serial_number = signer_id.getSerialNumber();

System.out.println ("Signer ID serial "+signer_id.getSerialNumber());
System.out.println ("Signer ID issuer "+signer_id.getIssuerAsString());


       CertStore cs = tsToken.getCertificatesAndCRLs ("Collection", "BC");

       Collection certs = cs.getCertificates (null);

       Iterator iter = certs.iterator();
       X509Certificate certificate = null;
       while (iter.hasNext()) {
           X509Certificate cert = (X509Certificate)iter.next();

if (cert_serial_number != null) {
if (cert.getSerialNumber().equals (cert_serial_number)) {
System.out.println ("using certificate with serial: "+cert.getSerialNumber());
certificate = cert;
}
} else {
if (certificate == null) {
certificate = cert;
}
}
System.out.println ("Certificate subject dn "+cert.getSubjectDN());
System.out.println ("Certificate serial "+cert.getSerialNumber());
}
tsToken.validate(certificate, "BC");
System.out.println ("TS info "+tsToken.getTimeStampInfo().getGenTime());
System.out.println ("TS info "+tsToken.getTimeStampInfo());
System.out.println ("TS info "+tsToken.getTimeStampInfo().getAccuracy());
System.out.println ("TS info "+tsToken.getTimeStampInfo().getNonce());
return tsToken;
}



}




Aleksandras S napisał(a):
Hi Tomek,
Can you show a code place where you add a timestamp?
Do you include in your signature dictionary "M" with time of signing?
On 19/05/06, *Tomek Maćkowski* <tmackowski (at) gmail.com <mailto:tmackowski (at) gmail.com>> wrote:


    Hi


I have a problem with timestamp of digital signature. I create this signature as 'adbe.pkcs7.detached ' and everything works fine. Now I want to add a timestamp to the signature (by adding ASN.1 'id-smime-aa-timeStampToken' atribute to PKCS7 signature as in RFC 3161 Appendix A). When i open this created pdf the signature is visible , it is verified, but acrobat reader does't show time of signature nor timestamp authority (on Data/Time tab of signature properties) only 'Not available' text is shown (it shows only info: siignature is timestamped but the timestamp could not be verified)

    When I open a sample document prepared by adobe which contains
    signature
    with timestampi can see signing date and timestamp authority.
    I think there is a problem of parsing the signature by security
    handler.


Do you have any ideas or expierences with timestamped signaatures?


------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 <http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642> _______________________________________________ iText-questions mailing list iText-questions (at) lists.sourceforge.net <mailto:iText-questions (at) lists.sourceforge.net> https://lists.sourceforge.net/lists/listinfo/itext-questions





------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ iText-questions mailing list iText-questions (at) lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/itext-questions