It would be great if GnuPG could manage first-party attestations of third-party certifications.
Below is a proposal for how the UI/API of GnuPG might enable this:
Retaining Attestation Key Signatures
GnuPG should retain the most recent cryptographically-valid self-signed Attestation Key Signatures it sees for each <Key,UserID> pairing. It should discard all superseded Attestation Key Signatures.
If the "most recent" Attestation Key Signature timestamp is shared by multiple Attestation Key Signatures, GnuPG should retain all of them.
For end-user-facing views, I see two alternatives:
- gpg --check-sigs could display whether a given certification is attested to, the same way that it shows (for example) L for "local" (non-exportable) certifications. The flag A could be used to mean "attested to". This is a bit tricky given the current implementation, because it means generating the output line based on information that is not internal to the certification.
- --list-options could grow a new parameter, show-unattested-sigs, which defaults to on. If the user wants to only see the attested sigs, they can use --list-options no-show-unattested-sigs.
A drawback to both of these proposals is that they don't offer the user a way to see attestations about certifications that the local installation knows nothing about. I'm not sure what the right way to do that is -- perhaps it doesn't matter? I could imagine something like gpg --list-unknown-attestations which would produce a list of digests, but that doesn't seem particularly meaningful or useful.
GnuPG doesn't have a standard way to identify individual certifications, and probably shouldn't try to build one only for this purpose. Instead, we offer the user a reasonable interface for doing sensible operations. Advanced users who need more sophisticated targeting can make do with a combination of these commands with "--edit-key delsig", but they are not the target users.
gpg --quick-add-attestations [--include-historic] <user-id> [<signer-id> …]
<user-id> can be either a UserID-matching string or a fingerprint, used to identify a set of certificates from those whose secret primary key we have access to. If <user-id> is a UserID-matching string, then the "subjects" are only the matched User ID(s) from those certificate(s). If <user-id> is a fingerprint, then the "subjects" are every User ID associated with the given primary key.
Each <signer-id> can be either a User ID matching string, or a fingerprint, used to identify a third-party whose certifications we want to attest to. The "third-parties" are the set of primary keys which match <signer-id>. Note that there can be multiple <signer-id>s. If there is more than one, then the "third-parties" are the union of all matching primary keys. if <signer-id> is "*", then the "third-parties" are all possible primary keys.
For each "subject", then:
- GnuPG assembles a list of certifications over the User IDs made by any of the "third-parties" (primary keys). This is the pool of new proposed attestations for this subject.
- Unless "--include-historic" was given, GnuPG removes from the pool all but the most recent certification from each third-party.
- GnuPG then calculates the digests of all certifications in the pool, yielding a proposed set of digests.
- GnuPG then takes the set of digests in the most recent Attestation Key Signature over the "subject" (or the empty set, if no AKS exists for "subject"), and inserts this pre-existing set into the proposed set.
- if the resulting proposed set is identical to the pre-existing set, then there is nothing to do, and GnuPG can terminate.
- Otherwise, GnuPG then makes a new Attestation Key Signature over the subject, covering exactly the members of the proposed set.
gpg --quick-remove-attestations [--remove-unknown] [--remove-historic] <user-id> [<signer-id> …]
<user-id> and <signer-id> match to select "subjects" and "third-parties" the same way as --quick-add-attestation, but what GnuPG does with them is different. For each "subject":
- GnuPG takes the set of digests in the most recent Attestation Key Signature over the "subject" (or the empty set, if no AKS exists). We populate the proposed set of digests to retain from this pre-existing set of digests.
- We take all digests that GnuPG can associate with specific certifications, and we group those certifications by issuer. For each issuer:
- If the issuer is one of the "third-parties", remove all associated digests from the proposed set.
- Otherwise, if more than one certification is in the set for this issuer, and "--remove-historic" was given, remove from the proposed set the digests of all but the most recent certifications.
- If "--remove-unknown" was given, remove all digests from the proposed set that GnuPG cannot associate with a certification (typically, because it doesn't know about the certification).
- If the proposed set is identical to the pre-existing set, there is nothing to do, and GnuPG can terminate.
- Otherwise, GnuPG makes a new Attestation Key Signature over the subject, covering exactly the members of the proposed set.