This is a Java implementation of a Time Stamp Authority using the Time-Stamp Protocol (TSP) as defined in RFC 3161 and RFC 5816. It uses Bouncy Castle and Quarkus under the hood.
The application utilizes GraalVM's Native Image technology, which leads to a very small memory footprint of about 10 MB and a near instant startup in about 50 milliseconds.
Docker images are automatically published to Docker Hub.
By default, the embedded H2 database writes its data to the /work/data/tsa.mv.db
file. Mounting a directory or a named
volume to the /work/data
will make the DB data persistent.
The keystore containing the certificate and private key used to sign the requests with is loaded
from /work/keystore.p12
by default.
There are two Docker Image variants: Native and JVM.
Native Images (e.g. dnl50/tsa-server:3.1.0
) are only available for x86-64
. The JVM variant
(e.g. dnl50/tsa-server:3.1.0-jvm
) is available for x86-64
and arm64
.
The main purpose of this application is to sign TSP requests using
the HTTP Protocol. The application therefore offers an
HTTP endpoint under /sign
which accepts POST
requests with the content type application/timestamp-query
. The
ASN.1 DER-encoded Timestamp Request must be supplied in the request body.
The following OpenSSL commands can be used to send a timestamp request for an existing file:
# create a timestamp request
openssl ts -query -data /path/to/file -sha512 -cert -out request.tsq
# send the request using cURL
curl -X POST --data-binary @request.tsq --header "Content-Type: application/timestamp-query" http://localhost:8080/sign -o response.tsr
The available REST endpoints are documented in a OpenAPI specification which can be downloaded from the release page.
The application exposes an WebSocket endpoint under /history/responses
. The JSON representation of every TSP
response will be broadcast there.
All Parameters mentioned below can be configured in variety of ways. Please refer to the Quarkus Documentation for more information.
Parameter Name | Mandatory | Default Value | Description |
---|---|---|---|
tsa.ess-cert-id-algorithm |
No | SHA256 | The hash algorithm which is used to calculate the TSA's certificate identifier (ESSCertIDv2). |
tsa.signing-digest-algorithm |
No | SHA256 | The hash algorithm which is used to calculate the TSP requests digest, which will be signed by the TSA. |
tsa.accepted-hash-algorithms |
No | SHA256,SHA512 | Comma-separated list of hash algorithm names/OIDs which are accepted by the Time Stamp Authority. |
tsa.policy-oid |
No | 1.2 | The OID of the policy under which the TSP responses are produced. |
tsa.keystore.path |
Yes | The path of the PKCS#12 archive containing the certificate and private key used to sign TSP requests. Prefixing the path with classpath: will result in the PKCS#12 archive from being loaded from the classpath (not supported in native image). |
|
tsa.keystore.password |
No | The password of the PKCS#12 archive. | |
tsa.include-tsa-name |
No | true | Specifies whether the tsa Field in the TSTInfo should include the subject of the certificate. |
By default, all log messages will be printed to STDOUT. Please refer to the Quarkus Documentation for further information on how to configure the log output.
The signing certificate used by the Time Stamp Authority must be an RSA, DSA or EC certificate with
an Extended Key Usage extension marked as critical.
The only KeyPurposeId
present in the sequence must be id-kp-timeStamping
(OID 1.3.6.1.5.5.7.3.8
).
You should use a certificate issued by a trusted third party for production use
To issue a signing certificate using a custom CA, you can use the following commands:
First, create a file named tsa-x509-extensions.cnf
with the following content:
[v3_ca]
basicConstraints = CA:TRUE
keyUsage = digitalSignature, keyCertSign
[usr_timestamping]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation
extendedKeyUsage = critical, timeStamping
This file contains the extension profiles which are used later.
Then create a new private key for the CA:
openssl ecparam -genkey -name secp384r1 -out ca.privkey
After that, create a CSR (Certificate Signing Request) for the CA certificate
openssl req -new -key ca.privkey -out cacertreq.pem
and sign it with CA's private key created before
openssl x509 -req -in cacertreq.pem -extfile tsa-x509-extensions.cnf -extensions v3_ca -key ca.privkey -out cacert.pem
After that you can create a new private key which will be used by the TSA to sign the timestamp requests:
openssl ecparam -genkey -name secp384r1 -out tsa.privkey
Then create a CSR for it
openssl req -new -key tsa.privkey -out tsacertreq.pem
and issue a certificate using the CA certificate and private key created before:
openssl x509 -req -in tsacertreq.pem -extfile tsa-x509-extensions.cnf -extensions usr_timestamping -CA cacert.pem -CAkey ca.privkey -CAcreateserial -out tsacert.pem
The TSA certificate and private key can then be put into a PKCS#12 keystore which can be used by the application:
openssl pkcs12 -export -CAfile cacert.pem -chain -in tsacert.pem -inkey tsa.privkey -out tsa-keystore.p12
In normal operation, no signing certificate is configured by default since you probably want to use your own/your
organizations key pair and not a self-signed key pair I issued to use in integration tests. Configuring a file system
path to a valid certificate for development is error-prone though. That's what the development mode is for. It is
automatically enabled when running Quarkus using the quarkusDev
Gradle Task. The dev mode has the following effects:
- application data is written into an in-memory Database which will be scrapped on application shutdown
- uses a self-signed EC certificate for signing TSP requests
The source code is formatted using the Eclipse Code Formatter. The formatter config file is located
under /eclipse-formatter.xml
. A custom import order configuration file os located under /spotless.importorder
. The
code can also be formatted using the Spotless Gradle Plugin. Just execute
the spotlessApply
Gradle Task and you are good to go!
This project is licensed under the terms of the MIT license.