Digital signature with timestamp in Java
Asked Answered
A

1

3

I have an issue creating a valid CMS signature with Bouncy Castle using a trusted timestamp. The signature creation works well (I want to include the signature to a PDF file), the signature is valid. But after I include a trusted timestamp to the signature's unsigned attribute table, the signature still stays valid, but the Reader reports that The signature includes an embedded timestamp but it is invalid. This leads me to believe, that the hash I timestamp is not the correct one, but I cannot seem to figure out what is the problem with it.

Signing code:

Store store = new JcaCertStore(Arrays.asList(certContainer.getChain()));

CMSSignedDataGenerator signedDataGenerator = new CMSSignedDataGenerator();
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA1withRSA");
signedDataGenerator.addSignerInfoGenerator(
                       infoGeneratorBuilder.build(contentSignerBuilder.build(certContainer.getPrivateKey()), (X509Certificate)certContainer.getSignatureCertificate()));
signedDataGenerator.addCertificates(store);
CMSTypedData cmsData = new CMSProcessableByteArray(data);
signedData = signedDataGenerator.generate(cmsData, false);
Collection<SignerInformation> ss = signedData.getSignerInfos().getSigners();
SignerInformation si = ss.iterator().next(); // get first signer (should be only one)
ASN1EncodableVector timestampVector = new ASN1EncodableVector();
Attribute token = createTSToken(si.getSignature());
timestampVector.add(token);
AttributeTable at = new AttributeTable(timestampVector);
si = SignerInformation.replaceUnsignedAttributes(si, at);
ss.clear();
ss.add(si);
SignerInformationStore newSignerStore = new SignerInformationStore(ss);
CMSSignedData newSignedData = CMSSignedData.replaceSigners(signedData, newSignerStore);

The createTSToken code:

public Attribute createTSToken(byte[] data) throws NoSuchProviderException, NoSuchAlgorithmException, IOException {
    // Generate timestamp
    MessageDigest digest = MessageDigest.getInstance("SHA1", "BC");
    TimeStampResponse response = timestampData(digest.digest(data));
    TimeStampToken timestampToken = response.getTimeStampToken();
    // Create timestamp attribute

    Attribute a = new Attribute(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken, new DERSet(ASN1Primitive.fromByteArray(timestampToken.getEncoded())));
    return a;
}

timestampData:

TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);
byte request[] = req.getEncoded();

URL url = new URL("http://time.certum.pl");
HttpURLConnection con = (HttpURLConnection) url.openConnection();

con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "application/timestamp-query");
con.setRequestProperty("Content-length", String.valueOf(request.length));

OutputStream out = con.getOutputStream();
out.write(request);
out.flush();

if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
    throw new IOException("Received HTTP error: " + con.getResponseCode() + " - " +                 con.getResponseMessage());
}
InputStream in = con.getInputStream();
TimeStampResp resp = TimeStampResp.getInstance(new ASN1InputStream(in).readObject());
response = new TimeStampResponse(resp);
response.validate(req);
if(response.getStatus() != 0) {
    System.out.println(response.getStatusString());
    return null;
}
return response;

Thanks for your help!

Example files:

Signed PDF

Unsigned PDF

Signed PDF with iText

Signed PDF with LTV - edited

Ahn answered 18/2, 2014 at 9:24 Comment(3)
Are you sure about your timestampData method? Can you furthermore provide a sample PDF signed and timestamped by your code?Festival
To be honest, I am not sure about anything anymore. :) I've added the timestampData method, plus uploaded a signed and an unsigned PDF example.Ahn
I'll look into this laterFestival
F
2

signed_lipsum.pdf, first version

The time stamp token references as signer some

CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU

which has been issued by

CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU

with serial number 7.

It does not provide this certificate itself, though, and neither is it provided by the encapsulating signature CMS container nor in some validation related information PDF document section.

Thus, at least on my computer there is no chance of verifying the time stamp token in any way and Adobe Reader is completely right not to accept the time stamp.

Have you provided the certificate in question on your computer in a way appropriate for your Adobe Reader? If you have and it still does not work, please supply it for further tests. If you have not, try to retrieve and provide them.

You might want to beef up the time stamp token itself to include that certificate before including it into the signature.

signed_lipsum.pdf, second version

In the updated file signed_lipsum.pdf the signature time stamp contains a TSA certificate, but it is the wrong one!

Just like in the first version the time stamp references a signer certificate with

  • Subject CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • Issuer CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • Serial number 7.

The contained certificate, on the other hand, has

  • Subject CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • Issuer CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • Serial number 5.

I assume that test TSA uses multiple signing devices / soft-tokens with individual certificates and the OP included the wrong one.

You, therefore, might want to include the correct certificate instead.

BTW, the time stamp in the PDF signed by iText contains a certificate matching the references in the stamp...

RFC 3161 time stamp requests can ask the TSA to include the signer certificate automatically. Bouncy Castle allows to set this flag like this:

TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
reqgen.setCertReq(true); // <<<<<<<<<<<<<<<<<<<<<<<<<<
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);

Instead of including the certificate yourself, you might try this.

LTV enabled

From the comments:

Just out of curiosity, what extra needs to be added to make a PDF LTV enabled?

To quote Leonard Rosenthol (PDF guru at Adobe):

LTV enabled means that all information necessary to validate the file (minus root certs) is contained within. So this statement [...] would be true.

the PDF is signed correctly and contains all necessary certificates, a valid CRL or OSCP response for every certificate

(Jan 10, 2013; 7:07pm;Leonard Rosenthol on itext-general)

Festival answered 19/2, 2014 at 8:59 Comment(23)
But shouldn't Reader say that the timestamp cannot be verified instead of saying that it is invalid?Ahn
Have a look at this answer - until some seemingly minor details of a time stamp were fixed, Adobe Reader claimed the document to have been changed. Furthermore I also have seen other software throwing NullPointerExceptions when not finding a signer certificate during verification...Festival
That been said, I cannot guarantee that this is the reason; it essentially is where I am stuck and Adobe Reader might be stuck there, too.Festival
I see, and how should I beef up the TimeStampToken? I get it's CMSSignedData structure and use the replaceCertificatesAndCRLs method to replace (add) the certificates I get by downloading it from the TSP. Do I understand correctly?Ahn
I'm not a BC expert but at first glance that seems to be what I mean.Festival
I have added the TSP's certificates to the timestamp token, but it still gives invalid timestamp error. I've updated the link to the signed PDF fileAhn
I have also added a signed PDF using iText, which shows that there is a valid timestamp that cannot be verified (but at least it is valid) so there should be some difference between the two, but I cannot figure out what it is :(Ahn
I took your new sample document and added the time stamping authority certificate to the trusted certificates in Adobe. Since then Adobe Reader has been happy with the time stamp. It is a test tsa after all, so you have to add it to your trusted certificates manually...Festival
Oh, i was a bit too quick. I thought the iText file was your new file and tested it. The above is true for that file, not your new attempt.Festival
Ok, your new file included the wrong certificate (correct issuer and subject but wrong serial number). I added to the answer accordingly.Festival
And it solved it! Your help is greatly appreciated! It is awesome that there are people like you :-)Ahn
Just out of curiosity, what extra needs to be added to make a PDF LTV enabled?Ahn
what extra needs to be added to make a PDF LTV enabled? - I added to the answer.Festival
Hi @mkl! I've been still stuck with making the PDF LTV enabled. I've included CRLs for all certificates, even the ones for the timestamp, but Adobe Reader still reports it as not LTV enabled. Could you please be kind, and take a look at it? I've updated the original question with the file. Thank you!Ahn
I'll look at your file tomorrow. A question first, though, have you also included the certificates the crls are signed with, and crls or ocsp responses for them?Festival
It should be included in my certificate chain, shouldn't it?Ahn
The certificates used for signing CRLs or OCSP responses can be different ones.Festival
Concerning lipsum_signed_1393179882.pdf - first of all there are no CRLs or OCSP responses for the time stamp certificate chain. But Adobe Reader furthermore seems to be unhappy with the CRL issued by CN=Certum CA,O=Unizeto Sp. z o.o.,C=PL, I'm not yet sure why.Festival
Well, there shouldn't be a CRL for that certificate :/Ahn
I have modified the last PDF, it should now contain a CRL for the timestamp and also I've added the Adobe Revocation attributes to the signed attributes table, and still no luck. I know I'm missing something small, but still don't know what exactly.Ahn
At lest your newest attempt shows the signature to be LTV enabled, merely the time stamp cannot be validated...Festival
I just cleaned up the trusted certificates in Adobe Reader from any leftovers from experiments with your documents and then only added your Certum CA to that list. Then I checked your newest document signed_1724252717318210996.pdf: Your signature and timestamp are shown as valid and LTV enabled! The document now is quite huge, though... ;)Festival
Whoa! Thanks for letting me know. I've just checked again, and without doing anything, it shows up as LTV enabled too. It seems like Adobe waits a couple of days after a signature was generated to make it LTV enabled? Strange! Thank you mkl for all your effort of helping me!Ahn

© 2022 - 2024 — McMap. All rights reserved.