Automatically create trusted timestamps for your commits
This software allows you to add timestamps to your contributions to a Git repository via trusted third-party timestamping services. As specified in RFC 3161, these timestamps may be used to prove the existence of data at the time the timestamp was issued and that the data wasn't changed since then. This timestamp data may serve to derive proofs of:
- Integrity of the data to be committed
- Ownership immediately before the commit
- Timeliness of the contributed work
- Authorship through self-disclosed copyright notices
All data used and generated by this software is stored in separate Git branches. You may choose freely to publish the timestamps or keep them private as needed. This software runs entirely client-side.
ℹ Note: Check out this software in action on this repo: sig/b/master
This software can be installed to any local Git repository. Clone this repository or download its source from the Releases page. Then choose one of the following ways to install:
Run the config.sh script with the path to the local repository you want to install automated timestamping to:
./config.sh ~/path/to/repo
- Copy the contents of hooks directory into the
.git/hooks
directory of the target repository. - Set the options described in the options section for at least the target repository.
- If you already have the hooks
commit-msg
,post-commit
,pre-push
in place, in your hooks:source
this software's renamed respective hook file- Call the
ts-commit-msg
/ts-post-commit
/ts-pre-push
function with the arguments the respective hook expects.
ℹ Note: if the script was installed into
.git/hooks
it is technically not part of the repository and will therefore not be versioned through commits nor sent to remotes through pushes.
⚠ Warning: If the repository you wish to install to already uses any of the hooks above, make sure the scripts of this software are run not parallel to other hooked scripts that read or modify the repository.
Run the config.sh script with the path to the local repository you want to uninstall automated timestamping from:
./config.sh -r ~/path/to/repo
If you don't want to keep the generated timestamps, run
./config.sh -p ~/path/to/repo
instead.
To remove automated timestamping from a repository (provided automatic installation preceded):
- Delete the
commit-msg
,post-commit
,pre-push
andtimestamping.sh
files from the.git/hooks
directory in the repository. - Unset the
ts.*
git-config options.
If you also want to delete any generated timestamps:
- Force-delete the
${ts.branch.prefix}/root
and${ts.branch.prefix}/b/*
(sig/root
andsig/b/*
by default) branches from the repository.
This software uses OpenSSL to generate timestamps according to the "Internet X.509 Public Key Infrastructure Time-Stamp Protocol" specified in RFC 3161.
Timestamps of your commits are automatically created on calling git-commit.
On committing, this will happen behind the scenes:
- Immediately before committing, a full diff (qualified for use with git-apply) of your staged changes / the staged state of the checked out branched is created.
- This diff is placed into a separate signing branch, corresponding 1:1 to your normal non-signing branches.
- The diff is then hashed, and a timestamping request for that hash is created in the signing branch for each time stamp authority you have configured.
- These timestamping requests are sent to the timestamping servers and the responses are also be stored in the signing branch.
- The diff, request and response files are then committed to the timestamping branch.
- Afterwards, your staged contributions are committed to the non-signing branch.
- This commit is then merged into its timestamping branch to relate the timestamp to it.
- Lastly, the branch you committed to is checked out again.
Timestamps are versioned in special signing branches, that match 1:1 to your regular branches. These branches have a separate root, so you may withhold them when publishing your contributions as a Git repository.
To find the timestamp of the latest you created by committing changes, check out the appropriate signing branch (provided default options) e.g.:
git checkout "sig/b/single"
to check out the timestamps created for commits on branch single
.
To find the timestamp of a specific commit, refer to this commit history graph:
┊ ┊
o │ <- Merged timestamp/actual commit
│╲│
│ o <- Actual commit
│ │
o │ <- Timestamp commit
│ ┊
┊ ┴ <- Actual branch
┴ <- Signing branch
As the timestamps are created before the actual commits, they can not refer to the actual commit. Therefore, the actual commit is merged into the signing branch afterwards, so that both the timestamp and actual commit are previous commits of this new merged commit. However, to keep contributions and timestamps separate, the merged commit still only contains the timestamp files.
You'll find the timestamp files from each configured TSA inside its respective configuration directory (provided default options) e.g.
./
├ .diff <- Full diff of the staged files before committing
└ rfc3161/
└ zeitstempel.dfn.de/
├ cacert.pem
├ request.tsq <- Timestamp request
├ response.tsr <- Timestamp
└ url
...
To verify the files against each other you may use these commands (provided default options):
-
Show a trusted timestamp's contents:
cd ./rfc3161/zeitstempel.dfn.de openssl ts -reply -in response.tsr -text
-
Verify a timestamp against the request:
cd ./rfc3161/zeitstempel.dfn.de openssl ts -verify -in response.tsr -queryfile request.tsq -CAfile cacert.pem
-
Verify a timestamp against the diff:
cd ./rfc3161/zeitstempel.dfn.de openssl ts -verify -in response.tsr -data ../../.diff -CAfile cacert.pem
A time stamp authority is a trusted third party that signs data provided to it using asymmetric keys together with the timestamp of receiving the data. With this, the TSA confirms that it was sent the signed data at the signed timestamp. This software utilises the "Time-Stamp Protocol via HTTP" described in RFC 3161 Section 3.4 for requesting timestamps.
You can configure an arbitrary number of individual TSAs for each repository. To configure a new timestamping server for a repository where this software is installed to, do the following steps:
-
Check out the branch specified through
ts.branch.prefix
(sig/root
by default).
Example:git checkout sig/root
-
In there, navigate to the directory specified in
ts.server.directory
(rfc3161
by default) and create a new directory. The name of this directory specifies the domain of the timestamp server.cd rfc3161 mkdir zeitstempel.dfn.de
If the URL of the timestamp server is a resource on a domain, you may name this directory anything and place a file named
url
(can be changed viats.server.url
) containing the URL inside it instead. -
Place the public certificate bundle of the timestamp server inside the directory as
cacert.pem
(can be changed viats.server.certificate
).
The repository should look like this afterwards (provided default options):./ └ rfc3161/ └ zeitstempel.dfn.de/ ├ cacert.pem (└ url) ...
-
Commit this addition to
sig/root
.
ℹ Note: For a ready-to-use list of timestamping servers, see docs/servers.md.
By placing additional files inside a TSA configuration's directory, you can further customize how timestamps from that TSA are generated. Here is a fully customized TSA configuration directory:
./
└ rfc3161/
└ freeTSA/
├ .diff
├ cacert.pem
├ cacert.sh
├ diff.sh
├ request.sh
├ request.tsq
├ response.sh
├ response.tsr
└ url
...
The following customizations are recognized:
-
File:
url
Description: If existent, defines the URL the timestamping request is sent to.
Use this to specify a protocol and resource on the server domain.Example:
./rfc3161/freetsa/url
https://freetsa.org/tsr
-
File:
cacert
.sh
Description: If existent, is called when before verifying the timestamp before the actual commit, and it's output is piped into the certificate bundle file of the TSA.
Use this to ensure the timestamps are verified against the current certificate.Example:
./rfc3161/freetsa/cacert.sh
curl --silent https://freetsa.org/files/cacert.pem
-
File:
diff
.sh
Description: If existent, is called when creating the diff before the actual commit, and it's output is used as a diff to timestamp from that TSA only. The so generated diff file will not be modified further.
Working directory is the repository's root directory.Example:
./rfc3161/freetsa/diff.sh
git diff --staged --full-index --binary
-
File:
request
.sh
Description: If existent, is called for creating the timestamping request.
The diff file will be supplied via stdin and the contents of the request file are expected on stdout.Example:
./rfc3161/freetsa/request.sh
openssl ts -query -cert -sha512 <&0
-
File:
response
.sh
Description: If existent, is called for retrieving the timestamping response.
The request will be supplied via stdin and the contents of the response file are expected on stdout.Example:
./rfc3161/freetsa/request.sh
curl --silent --header 'Content-Type: application/timestamp-query' --data-binary @- https://freetsa.org/tsr <&0
You may want to change the configuration of a TSA if the URL to the server or the certificate bundle of the server change. To do so (provided default options):
- Change the associated files/directory on branch
sig/root
. - Commit the changes to
sig/root
.
Upon committing to the sig/root
branch, the timestamps for the changed TSA configurations will be updated for all branches
that already have a timestamp of the previous version of the TSA configuration.
To delete a TSA configuration (provided default options):
- Delete the associated directory in
rfc3161
on branchsig/root
. - Commit deleting the directory to
sig/root
.
This software is controlled via git-config. These options all occupy the ts.
namespace. They can be set via
git config <option> "<value>"
Git config option | Description | Default value |
---|---|---|
ts.branch.prefix |
The prefix used for branches created through and used by the automated timestamping. Will be appended with /root for root branch and with /b/<branch-name> for each branch committed to. |
"sig" |
ts.branch.pull |
How remote and local signing branches should me managed. May either be:
|
"merge" |
ts.branch.withhold |
Whether the contents of timestamping branches should be withheld from remotes. If true , git-push will fail for timestamping branches. |
"false" |
ts.commit.prefix |
The prefix used for messages for commits containing timestamps. Will be appended with the commit message of the actual commit. |
"Timestamp for: " |
ts.commit.options |
Options to apply to the git commit command for committing timestamps. |
"" |
ts.commit.relate |
Whether timestamp commits should be related via merge commits. May be true or false . |
"true" |
ts.diff.notice |
Text added to the start of the timestamped diff files. | "Written by $(git config --get user.name)" |
ts.diff.file |
Name of the generated diff file. | ".diff" |
ts.diff.type |
Type of diff to be created. May either be:
|
"staged" |
ts.server.directory |
The directory containing the timestamp server configurations relative to the repository's root directory. | "rfc3161" |
ts.server.url |
Name of the file containing the url of the timestamp server. | "url" |
ts.server.certificate |
Name of the certificate bundle file for a single timestamp server. | "cacert.pem" |
ts.server.update |
Whether timestamps should be updated on TSA configuration changes. May be true or false . |
"true" |
ts.request.file |
Name of the generated timestamp request file. | "request.tsq" |
ts.request.options |
Options for creating the timestamp request file through openssl ts -query . |
"-cert -sha256 -no_nonce" |
ts.response.file |
Name of the received timestamp response file. | "response.tsr" |
ts.response.options |
Options for requesting the timestamp from the server through curl . |
"" |
ts.response.verify |
Whether the received timestamp should be verified against the diff and request file. May be true or false . |
"true" |
ts.enabled |
Whether automated timestamping should be triggered on commits. May be true or false . |
"true" |
⚠ Warning: Set the paths and filenames so that they don't interfere with what you plan to commit.
- Automatically creating RFC3161 timestamps
- Multiple TSAs
- Choice between cached and full diffs
- Custom timestamp response options
- Referencing actual commits in timestamping branches
- Automatically redoing timestamps upon configuration changes
- Withholding timestamping commits from remotes
- Prevent merging timestamping commits into actual branches
- Custom diff and timestamp generation per TSA
- Trusted timestamps after commits
This software is released under the MIT License.