Hello!
I have a p7m file generated using the BC provider. The certificate used for signing is a self signed certificate.
My signed file is generated using the following code
Code:
List<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add(getCertificate(alias));
CertStore certstore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), "BC");
CMSSignedDataGenerator signer = new CMSSignedDataGenerator();
signer.addSigner(getPK(alias), getCertificate(alias), CMSSignedDataGenerator.DIGEST_SHA1);
signer.addCertificatesAndCRLs(certstore);
CMSProcessable cmsUnsigned = new CMSProcessableByteArray(unsignedBytes);
CMSSignedData signedData = signer.generate(cmsUnsigned, true, "BC");
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(unsignedBytes);
byte hash[] = messageDigest.digest();
signedData = addTimestamp(signedData, getTimeStampToken(1, hash));
After generating the signed file, I'm adding the timestamp from a TSA, using the addTimestamp method; the timestamp token is read using the getTimeStampToken method. Here is the listing of the 2 methods
Code:
private static TimeStampToken getTimeStampToken(int TSA, byte[] digest) 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 (true);
//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));
digest, 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");
HostConfiguration hc = new HostConfiguration();
hc.setProxy("proxy.stfd.ro", 3128);
HttpClient http_client = new HttpClient();
http_client.executeMethod(hc, 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().getAccuracy());
System.out.println ("TS info "+tsToken.getTimeStampInfo().getNonce());
return tsToken;
}
Code:
private static CMSSignedData addTimestamp(CMSSignedData signedData, TimeStampToken tok) throws Exception {
Collection ss = signedData.getSignerInfos().getSigners();
SignerInformation si = (SignerInformation) ss.iterator().next();
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);
ASN1EncodableVector dv = new ASN1EncodableVector();
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;
}
The timestamp is set as an unsigned attribute, as stated in RFC3161, appendix A.
My problem is that when I try to verify as stated in the same RFC,
Quote:
The value of messageImprint field within TimeStampToken shall be a
hash of the value of signature field within SignerInfo for the signedData being time-stamped.
|
the following code returns false
Code:
private boolean verifyTimestamp(CMSSignedData signature, TimeStampToken tto) throws Exception{
System.out.println("******************************** start verify timestamp");
readTimestampToken(signature);
byte[] hashB = null;
byte[] hashC = null;
hashC = getHash(this.signedHash);
hashB = tto.getTimeStampInfo().getMessageImprintDigest();
System.out.println("******************************** end verify timestamp");
return Arrays.equals(hashB, hashC);
}
The timestamp token is being read from the signed file
Code:
private TimeStampToken readTimestampToken(CMSSignedData signature) throws Exception{
TimeStampToken tto = null;
SignerInformationStore signers = signature.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
SignerInformation signer = (SignerInformation)it.next();
AttributeTable attrs = signer.getUnsignedAttributes();
this.signedHash = signer.getSignature();
Attribute att = attrs.get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
DEREncodable dob = att.getAttrValues().getObjectAt(0);
CMSSignedData signedData = new CMSSignedData(dob.getDERObject().getEncoded());
tto = new TimeStampToken(signedData);
return tto;
}
Any idea what the problem might be?
I believe that I'm doing something wrong is when generating the signature with the timestamp but I cannot find it...
Any help would be appreciated!
Thank you,
Alexandru