Signature timestamp
- From: Tomek Maćkowski <tmackowski (at) gmail.com>
- Date: Fri, 19 May 2006 09:19:52 +0200
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