Attached you'll find 2 file:
signAndTimestamp.java: just contains the method that performs signature and
timestamp
TimeStampService.java: contains the code used to send the timestamp request
to the timestamp server
I've attached both files, so that users can be able to get a full working
example.
Let me know if you need something else.
Regards,
Massimiliano Ziccardi
private static void signAndTimestamp(File fIn, File fOut, File KeyStoreFile, String sKeyStorePassword, String sPrivateKeyLabel, String sCertificateChainAlias)
{
try
{
Security.addProvider(new BouncyCastleProvider());
// Load the keys from the keystore.
KeyStore ks = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
ks.load(new FileInputStream(KeyStoreFile), sKeyStorePassword.toCharArray());
PrivateKey privKey = (PrivateKey) ks.getKey(sPrivateKeyLabel, sKeyStorePassword.toCharArray());
Certificate[] certChain = ks.getCertificateChain(sCertificateChainAlias);
PdfReader reader = new PdfReader(fIn.getAbsolutePath());
PdfStamper stp = PdfStamper.createSignature(reader, new FileOutputStream(fOut), '\0');
PdfSignatureAppearance sap = stp.getSignatureAppearance();
sap.setVisibleSignature(new Rectangle(100, 100, 300, 200), 1, null);
// If you have a labeled signature field, use the following line instead of the previous one
// sap.setVisibleSignature("SIGNATURE_FIELD_NAME");
sap.setCrypto(null, certChain, null, null);
sap.setReason("I like to sign");
sap.setLocation("Universe");
sap.setAcro6Layers(true);
sap.setRender(PdfSignatureAppearance.SignatureRenderNameAndDescription);
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
dic.setDate(new PdfDate(sap.getSignDate()));
dic.setName(PdfPKCS7.getSubjectFields((X509Certificate) certChain[0]).getField("CN"));
if (sap.getReason() != null)
dic.setReason(sap.getReason());
if (sap.getLocation() != null)
dic.setLocation(sap.getLocation());
sap.setCryptoDictionary(dic);
// 8000 bytes should be enough to contain the signature. If you get errors about a too small buffer, resize this accordingly
int csize = 8000;
HashMap exc = new HashMap();
exc.put(PdfName.CONTENTS, new Integer(csize * 2 + 2));
sap.preClose(exc);
MessageDigest md = MessageDigest.getInstance("SHA1");
InputStream s = sap.getRangeStream();
int read = 0;
byte[] buff = new byte[8192];
while ((read = s.read(buff, 0, 8192)) > 0)
{
md.update(buff, 0, read);
}
byte[] hash = md.digest();
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
// Create an AttributeTableGenerator to create the signature timestamp token
CMSAttributeTableGenerator unsignedAttributeTableGenerator = new CMSAttributeTableGenerator()
{
public AttributeTable getAttributes(final Map parameters) throws CMSAttributeTableGenerationException
{
AttributeTable attributeTable = null;
// Gets the signature bytes
byte[] signatureBytes = (byte[]) parameters.get(SIGNATURE);
DERObject obj;
try
{
// digests the signature
MessageDigest d = MessageDigest.getInstance("SHA1");
byte[] signatureHash = d.digest(signatureBytes);
// Sends the request to the timestamp server
TimeStampService tss = new TimeStampService(TIMESTAMP_SERVER_URL, TIMESTAMP_SERVER_PORT, TIMESTAMP_POLICY_OID);
obj = new ASN1InputStream(tss.requestTimeStamp(signatureHash).getEncoded()).readObject();
// Creates the signatureTimestampToken attribute
DERSet s = new DERSet(obj);
Attribute att = new Attribute(TimeStampService.id_signatureTimeStampToken, s);
Hashtable oh = new Hashtable();
oh.put(TimeStampService.id_signatureTimeStampToken, att);
attributeTable = new AttributeTable(oh);
return attributeTable;
}
catch (Exception e)
{
throw new CMSAttributeTableGenerationException(e.getMessage(), e);
}
}
};
generator.addSigner(privKey, (X509Certificate) certChain[0], CMSSignedDataGenerator.DIGEST_SHA1, new DefaultSignedAttributeTableGenerator(), unsignedAttributeTableGenerator);
List chainAndCrls = new ArrayList();
if (certChain != null)
chainAndCrls.addAll(Arrays.asList(certChain));
// If you have crls:
// if (crls != null)
// chainAndCrls.addAll(Arrays.asList(crls);
CertStore chainStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(chainAndCrls), "BC");
generator.addCertificatesAndCRLs(chainStore);
CMSProcessable content = new CMSProcessableByteArray(hash);
CMSSignedData signedData = generator.generate(content, true, "BC");
byte[] signedDataDerBytes = signedData.getEncoded();
byte[] outc = new byte[csize];
PdfDictionary dic2 = new PdfDictionary();
System.arraycopy(signedDataDerBytes, 0, outc, 0, signedDataDerBytes.length);
dic2.put(PdfName.CONTENTS, new PdfString(outc).setHexWriting(true));
sap.close(dic2);
}
catch (Exception e)
{
e.printStackTrace();
}
}
package it.security.timestamp;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.tsp.TSPAlgorithms;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampToken;
/**
* This object implements the timestamp protocol
* .
* @author Massimiliano Ziccardi
*
*/
public class TimeStampService
{
/**
* The OID of the signature timestamp token
*/
public static final DERObjectIdentifier id_signatureTimeStampToken = new DERObjectIdentifier("1.2.840.113549.1.9.16.2.14");
/**
* The Policy OID
*/
private String m_sPolicyOID = null;
/**
* The hostname or IP address of the Timestamp Server
*/
private String m_sHost = null;
/**
* The port of the Timestamp Server. Default is 318.
*/
private int m_iPort = 318;
/**
* Instantiate and initializes the timestamp service object
* @param sHostname The hostname or IP address of the Timestamp Server
* @param iPort The port of the Timestamp Server. Default is 318.
* @param sPolicyOID The Policy OID
*/
public TimeStampService(final String sHostname, final int iPort, final String sPolicyOID)
{
super();
m_sHost = sHostname;
m_iPort = iPort;
m_sPolicyOID = sPolicyOID;
}
/**
* Sends the timestamp request to the timestamp server and
* returns the received TimeStampToken
*
* @param digest - the data to be timestamped
* @return the time stamp generated by the time stamp server.
* @throws TSPException - on any timestamp error
* @throws IOException
*/
public TimeStampToken requestTimeStamp(final byte digest[])
throws TSPException, IOException
{
TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
reqgen.setReqPolicy(m_sPolicyOID);
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, digest);
byte request[] = req.getEncoded();
int length = request.length + 1;
Socket s = new Socket(m_sHost, m_iPort);
s.setSoTimeout(5000);
OutputStream os = s.getOutputStream();
os.write((byte) (length >> 24));
os.write((byte) (length >> 16));
os.write((byte) (length >> 8));
os.write((byte) length);
os.write(0);
os.write(request);
DataInputStream is = new DataInputStream(s.getInputStream());
length = is.readInt() - 1;
if (is.readByte() == 10)
{
is.readChar();
length -= 2;
}
byte response[] = new byte[length];
is.readFully(response);
s.close();
ASN1InputStream in = new ASN1InputStream(response);
DERSequence asn = (DERSequence) in.readObject();
DERSequence info = (DERSequence)asn.getObjectAt(0);
DERInteger status = (DERInteger)info.getObjectAt(0);
if(status.getValue().intValue() != 0 && status.getValue().intValue() != 1) throw new TSPException("Timestamp server error");
try
{
return new TimeStampToken(new CMSSignedData(asn.getObjectAt(1).getDERObject().getDEREncoded()));
}
catch (TSPException e)
{
throw e;
}
catch (Exception e)
{
throw new TSPException(e.getMessage(), e);
}
}
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
iText-questions mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/itext-questions
Buy the iText book: http://www.1t3xt.com/docs/book.php