6.2 KiB
RFC 0001 - A stable and forwards compatible public key storage format
Feature Name: Stable public key storage
Status: Draft (first parts sketched)
Type: Enhancement
Start Date: 2018-06-14
Author: Simon Massey
Related components: Core
GitHub issues:
- #136 GnuPG2 2.2 vs 2.1 conflicts in keybox format
Summary
A new internal public key storage format that avoids forwards compatibility issues between GPG releases. This proposal will keep forwards compatibility with older versions of git-secret.
Motivation
GPG maintains backwards compatibility but not forwards compatibility. Running a new GPG version can and will upgrade the keyring storage files in a way that is not recognised by older versions of GPG. This is not normally a problem for typical GPG usage. Users only upgrade and rarely downgrade. It is a problem for git-secret as the keyring storage is committed to git and shared between users. Someone using an older version of GPG can no longer open the upgraded keyring file.
Approach
git-secret will move away from using the keyring format as shared storage of public keys. Instead it will store public keys as separate files. The export format is stable and forwards compatible. It is normal for GPG users to be running different versions and to exchange keys successfully. Any future bugs that effect git-secret's ability to use the files will affect typical GPG key exchange usage. Such bugs are likely to be fixed by the wider GPG community.
git-secret may need to store and process meta-data about keys to make it efficient to work with keys that are individually stored. It will use the machine-readable "colon listings format" for this purpose.
It is anticipated that bash
and gawk
will be sufficient to be able to implement and use the new shared key storage format.
Design
The storage format will be:
- Keys will be stored in
~/.gitsecret/keys
ingpg --armor --export
format. The use of ASCII armour rather than binary format is to make debugging of key issues easier. The filename of the key will be the "64-bit keyid" (field 5 of thecolon listings
format)<keyid>.pub.gpg
- Key meta data will be stored alongside the key file in the
gpg --keyid-format long --with-colons
format. The file name will be<keyid>.gpg.colon
- A "keyring cache" will be created at
~/.gitsecret/cache
and this folder will be added to.gitignore
. At this location, a public keyring will be maintained on a per user bases and it won't be shared by users. - A tombstone marker file with
.killed
will be created at~/.gitsecret/keys
by git-secret-killperson to mark a user as killed.
git-secret-tell will:
- Scan the set of
.gpg.colon
to find all currently told identities. If the told identity is in the list do nothing. - If the told identity isn't listed run
gpg --armor --export
against the users$HOME
keyring. Run--keyid-format long --with-colons
of the exported key. The result being two new files<key-id>.pub.gpg
and<key-id>.gpg.colon
in~/.gitsecret/keys
Note that the additional steps to ensure that older versions of git-secret know about the newly told user will be outlined below.
git-secret-hide will:
- The list of "64-bit keyid"s who are told will be computed from the
.gpg.colon
files. This will be checked against the list of "64-bit keyid"s in the "keyring cache" at~/.gitsecret/cache
. Any missing keys are imported into the "keyring cache". It is anticipated thatgrep
andgawk
will be sufficient to perform this calculation. The code then runs as before using the "keyring cache".
git-secret-whoknows will:
- The list of identities will be loaded by parsing the
.gpg.colon
files. Note that multiple identities can be listed against each key.
git-secret-usage will:
- Document the git-secret-migrate command discussed in the next section.
git-secret-reveal will:
- Be unchanged.
git-secret-remove will:
- Be unchanged.
git-secret-list will:
- Be unchanged.
git-secret-killperson will:
- Remove the key from the keyring cache then delete the
<key-id>.pub.gpg
and<key-id>.gpg.colon
in~/.gitsecret/keys
.
git-secret-init will:
- Add
~/.gitsecret/cache
into.gitignore
and do any initialisation work of the public keyring at that location.
git-secret-clean will:
- Be unchanged.
git-secret-changes will:
- Show differences the files
<key-id>.pub.gpg
and<key-id>.gpg.colon
in~/.gitsecret/keys
git-secret-add will:
- Be unchanged.
A new command git-secret-migrate will:
- Create the folder
~/.gitsecret/cache
and add it to the.gitignore
file. - Extract any keys from the old keyring generating
<key-id>.pub.gpg
and<key-id>.gpg.colon
files in~/.gitsecret/keys
Version Compatibility
Backwards compatibility will the old keyring storage approach will be maintained as follows:
- For each changed command a guard will be added that checks for the existence of the .gitsecret/cache
- If the folder exists it proceeds as normal.
- If it does not exist it will report that the repo was initialised by an older version of git-secret and tell the user to run git-secret-migrate
Forwards compatibility with older versions of git-secret will be maintained as follows.
git-secret-hide will:
- Have a guard that will check for the existence of the old keyring. If it exists it will check it for any new public keys and extract them into the new format prior to running.
git-secret-tell will:
- Will check for the existence of the old keyring. If it exists it will load the new public key into it.
Drawbacks
To maintain forward compatibility the approach requires the existing logic to kept working for a period of time. We can give a deprecated warning if the forwards compatibility logic is running. The warning can be suppressed using a command-line flag.
Alternatives
What other designs have been considered? Unknown.
What is the impact of not doing this? Team members are locked out of secrets when only one other team member upgrades GPG. This can go undetected until the victim needs the secrets in a hurry for production support. Bad things then happen.
Unresolved questions
What parts of the design are still to be done? See TBD points above.