Weisser Zwerg Logo

Weisser Zwerg

RFC3161 Trusted Timestamping via OpenSSL by foot: a guided tour.

Published by Weisser Zwerg Blog on

A blog post to explain how to use the standard functionality of OpenSSL to create trusted timestamps for free.


Sometimes it is useful to be able to prove that a certain file, or more generally a state of the world (like a full git repository or similar), was present in that exact form latest at a given timestamp. For that purpose rfc3161 “Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)” exists.

In this blog post I’ll explain how to use the standard functionality of OpenSSL to achieve that.

Free Implementations

In order to create a trusted timestamp we will need an ideally free trusted timestamping service. The following git gist provides a List of free rfc3161 servers.

Trusted Timestamp with the Apple RFC3161 Server

The relevant links for the Apple RFC3161 Server are the following:

Create the timestamp response

First we will have to create a file that we want to timestamp and create a hash (aka digest):

> echo "testmessage" > state.txt
> openssl dgst -sha3-256 state.txt
>  SHA3-256(state.txt)= e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4

Above I used the SHA3 256 bit hash function with the following result: e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4.
256 bits means 32 bytes means 64 nibbles means 64 characters in the hexadecimal notation (go ahead and count).

Once we have the hash we can create a timestamp query:

> openssl ts -query -digest 'e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4' -sha256 -cert -out ts_req.tsq

We are specifying the parameter -sha256 rather than -sha3-256, because RFC3161 does not know about -sha3-256. Anyway, this parameter here is only used to specify the size of the digest and that is 256 bits.

Next we can use curl to talk to the Apple RFC3161 Server and ask for the actual timestamp response:

> curl http://timestamp.apple.com/ts01 -H 'Content-Type: application/timestamp-query' -s -S --data-binary "@ts_req.tsq" -o "ts_req.tsr"

We then can look at the resulting timestamp response file ts_req.tsr:

> openssl ts -reply -in ts_req.tsr -text

In the output you can see the Status: Granted. and the Message data that corresponds to our sha3-256 hash and of course the timestamp Time stamp: Mar 12 09:52:44 2022 GMT.

Status info:
Status: Granted.
Status description: Operation Okay
Failure info: unspecified

TST info:
Version: 1
Policy OID: 1.2.3
Hash Algorithm: sha256
Message data:
    0000 - e2 21 71 69 4f d8 e4 24-05 50 f9 95 c5 58 bc c9   .!qiO..$.P...X..
    0010 - 67 b3 df 0e 92 8b 51 a7-46 b2 cb a2 6f 6d 9e a4   g.....Q.F...om..
Serial number: 0x706F261A1B4E8986
Time stamp: Mar 12 09:52:44 2022 GMT
Accuracy: 0x01 seconds, unspecified millis, unspecified micros
Ordering: no
Nonce: 0xFD8CB0CAAEA28D69
TSA: unspecified

Woderful. This is the piece of data that you have to store somewhere safe so that later you’re able to proof that the original file (state.txt in our case) existed at or before the given timestamp.

Verify the timestamp response together with the referenced piece of data

How do we then verify the timestamp response?

You again create the digest of the file, which we already know: e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4.
In addition we’ll need the complete certificate chain for the Apple timestamp service. The locations of the certificates are documented on the relevant web-site at: https://www.apple.com/certificateauthority/
For our case we need the AppleTimestampCA.cer and the AppleIncRootCertificate.cer in PEM format. You can recognize this PEM format, because it is a simple text format that starts with -----BEGIN CERTIFICATE----- and ends with -----END CERTIFICATE-----.

Download the first certificate and check that it is in the right format:

> curl --remote-name https://www.apple.com/certificateauthority/AppleTimestampCA.cer

You should see that it is already in PEM format. You can also check who issued this certificate:

> openssl x509 -in AppleTimestampCA.cer -noout -issuer
>  issuer=C = US, O = Apple Inc., OU = Apple Certification Authority, CN = Apple Root CA

If you want to see more details about the certificate I recommend using the graphical gcr-viewer tool:

> gcr-viewer AppleTimestampCA.cer

At that point I was hoping that the Apple Root CA certificate would be part of the /usr/share/ca-certificates/mozilla certificates, which come from the Mozilla’s CA Certificate Program. See also the Included Certificates page. For whatever reason the Apple Root CA certificate is not present in there. I was trying to google to find why, but did not come up with a good answer. Be it as it may, this means we also have to download the root certificate, which we do next.

> curl --remote-name https://www.apple.com/appleca/AppleIncRootCertificate.cer

And for whatever reason this certificate is now not in PEM format, which means we have to convert it:

> openssl x509 -inform der -in AppleIncRootCertificate.cer -out AppleIncRootCertificate.pem
> openssl x509 -in AppleIncRootCertificate.pem -noout -issuer
>  issuer=C = US, O = Apple Inc., OU = Apple Certification Authority, CN = Apple Root CA

You can see in the above output that the cerfificate is self-signed by the Apple Root CA.

Once we have the cerficiates we can now finally verify our timestamp response with the hash/digest to see if the timestamp is valid:

> openssl ts -verify -digest e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4 -in ts_req.tsr -CAfile AppleTimestampCA.cer -partial_chain
>  Verification: OK
> openssl ts -verify -digest e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4 -in ts_req.tsr -CAfile AppleIncRootCertificate.pem -untrusted AppleTimestampCA.cer
>  Verification: OK

In the first call to openssl we used the -partial_chain argument to only verify against the Apple Timestamp Certification Authority certificate. Via the -CAfile argument we tell OpenSSL which certificates we trust. As we downloaded both certificates, the Apple Timestamp Certification Authority certificate and the Apple Root CA certificate from the same web-site I would not know why I would trust one more than the other. But the second command shows how you check the timestamp response only trusting the Apple Root CA certificate (-CAfile argument) and checking the full chain of trust from the Apple Timestamp Certification Authority certificate (-untrusted) to the Apple Root CA certificate.

One further, a bit advanced use, is to extract the certificate chain from the timestamp response. We asked the timestamp server to include the full certificate chain via the -cert argument above in the ts -query:

> openssl ts -query -digest 'e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4' -sha256 -cert -out ts_req.tsq

We can extract the certificate chain by first converting the timestamp response into token form and then extracting the certificate chain:

> openssl ts -reply -in ts_req.tsr -token_out -out token.tk
> openssl pkcs7 -inform DER -in token.tk -print_certs -outform PEM -out certificatechain.pem

If you look into it via for example gcr-viewer you’ll see that we have 3 certificates in there:

> gcr-viewer certificatechain.pem
  • Timestamp Signer MA1
  • Apple Timestamp Certification Authority
  • Apple Root CA

We can also verify the timestamp response via:

> openssl ts -verify -digest e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4 -in ts_req.tsr -CAfile AppleIncRootCertificate.pem -untrusted certificatechain.pem

This basically says that we trust the Apple Root CA certificate but that the full remaining certificate chain should be verified.

One additional option that might be useful is the -no_check_time option. It might be that the final certificate that was used to sign the timestamp query has expired, but the rest of the certificate chain is still valid. Then you might want to ignore the expiry of the leaf certificate.

> openssl ts -verify -no_check_time -digest e22171694fd8e4240550f995c558bcc967b3df0e928b51a746b2cba26f6d9ea4 -in ts_req.tsr -CAfile AppleIncRootCertificate.pem -untrusted certificatechain.pem

Further and advanced use-cases

Imagine that you’d like to use a git repository as a tamperproof file archive for your business accounting, then you could use these RFC3161 timestamps together with native git functionality to achieve that as described here:

In such a case you would also want your git repository to be encrypted on the remote host, even when you’re using a private repository. In that case you could use functionality provided by keybase.io:

I hope this blog post is useful to you and I am as always happe to receive feed-back!


Have you written a response to this? Let me know the URL via telegraph.

No mentions yet.