More on signatures and key revocation
Signature structure
First of all an obvious fact: a signed artifact should refer to the key used to sign it, so that the same key can be used for verification.
This is important because the artifact cannot simply refer to the user that authored it. This information is important because it is what we ultimately want to assess checking the signature, but the signature check needs an actual key.
Therefore a signature should contain three pieces of information (plus, obviously, the signature itself):
- A user identity (which resolves to the user metadata file).
- A “local reference” to one of the keys stored in the metadata file.
- Since that “local reference” is not guaranteed to be globally stable in time (i.e. the key could have been revoked or, more subtly, different user metadata files could “name” different keys in the same way), the exact revision of the user metadata file that was valid at the time in which the artifact has been signed.
Using those three pieces of information a key is unambiguously identified and can be used to check the signature.
If the check succeeds we can have confidence that the signed item has in fact been authored by the referred user.
Key revocation and timestamps
To revoke a key the simplest thing to do seems to be generating a new revision of the metadata file without the revoked key.
Older signatures referring to previous revisions would still be valid and new signatures should refer to newer revisions which lack the revoked key.
The key here is that “should”: a malicious user that gained control of the corresponding private key could still generate signatures referring to older revisions, which by definition should be valid.
The point is that the revocation should mark a given moment in time: signature before that moment are still valid and signatures after that moment should be retroactively invalidated.
The problem here is that we lack a global, shared timeline encompassing different repositories (the one of the metadata files and the ones of signed artifacts).
We would have this timeline on a blockchain but here we operate on a set of independent repositories.
The best I can think of is the following:
- Each user metadata file (and perhaps specifically each key revocation) should carry a UTC timestamp.
- Each signed artifact (each signature) should also carry a UTC timestamp.
- In every repository these timestamps should guaranteed to be monotonic, perhaps with a given small tolerance.
Thanks to the third point it should be impossible to sign artifacts with a timestamp in the past, or at least “too much” in the past: specifically, with a timestamp preceding the previous one in the current branch timeline.
Therefore, while it is technically possible to use a revoked key to produce a signature that would, by itself, look valid, it should be impossible to use such a signature for an artifact inside a history that already contains timestamps past the revocation point.
Unless one tries a history rewrite, which hopefully should be impossible because the history itself should be protected by other signatures (but I’d like somebody to think more about this).