We propose an SKS-specific Trust Packet format to store and sync data that cannot be otherwise represented as part of a certificate/TPK. Such metadata would be synced between SKS peers but stripped when served to clients over HKP.
Motivation
Keyservers may wish to store and sync config and metadata such as blocklist entries, out of band proofs, index keywords, etc. While this could be done using an additional side-band protocol, it would be elegant and efficient if metadata could be transferred using the existing SKS sync process.
Design
Original PGP used a trust packet body consisting of two uint8 fields denoting key/userid trust, and cached signature verification state. GnuPG extended this with four domsep bytes: three UTF-8 bytes containing “gpg”, and one uint8 field denoting the context (0=signature, 1=key, 2=userid), followed optionally by further GnuPG-specific fields. A trust packet immediately follows the "trustable" packet to which it refers, before any signatures over that packet (internally, GnuPG treats it as an extension of the preceding packet).
The SKS trust packet follows the above wire format up to and including the domsep fields, to minimise the risk of breaking a legacy parser if encountered unexpectedly.
The body of an SKS trust packet is as follows:
- Two uint8 zero bytes
- Four domsep bytes:
- Three UTF-8 application context bytes, containing either “sks” or “SKS”
- One uint8 packet context byte, containing the type ID (tag) of the preceding non-trust packet, or 0 (see below)
- A signature subpacket area consisting of the rest of the packet body
Metadata should generally be stored as notation subpackets, but other subpacket types may also be included if appropriate, such as embedded signatures.
The SKS trust packet comes in two forms:
-
A “quiet SKS trust packet” has a lowercase application identifier of “sks”, and is omitted from SKS digest calculations. It is therefore only synced as a side effect of another update, and is used for non-critical metadata. It can be safely served to legacy peers, as they will silently discard it.
-
A “noisy SKS trust packet” has an uppercase application identifier of “SKS”, and its contents up to the end of the first subpacket are included in SKS digest calculations. If it is not present on both sides, it will therefore cause sync failure, so is used only for critical information, or where sync failure is unavoidable (e.g. with mismatched blocklists)
Noisy trust packets are particularly useful where the trust packet itself is the only available data, for example when a key has been blocked. Since there is no associated certificate data, the trust packet must contribute to the SKS hash, otherwise all entries would have the same hash and would not sync. Similarly, if more than one noisy trust packet was permitted in a TPK, their contributions to the SKS hash should differ. Noisy trust packets MUST therefore be bitwise distinct up to the end of the first subpacket; this can be achieved by several means:
- In the case of a bare trust packet standing in for a blocked primary key, the version-tagged fingerprint of the primary key for which it is a surrogate is included in the first subpacket.
- Otherwise, the SKS hash of the preceding non-trust packet (the "trustable" packet) SHOULD be included in the first subpacket.
For most use cases a quiet trust packet should be employed instead.
Noisy trust packets MUST NOT contain any superfluous metadata in the first (hashed) subpacket, such as the generating server or application, or a timestamp. Multiple servers could independently create semantically-equivalent packets and if the hashed subpackets were not binary identical they would never resolve. Such metadata MUST be contained in the subsequent (unhashed) subpackets.
Unlike GnuPG, which permits at most one trust packet per "trustable" packet, SKS imposes no such restriction - this allows trust packets from multiple sources to be aggregated.
Examples of interactions
Enumerable domains
A redacted certificate may contain a quiet trust packet on the primary key, with notations denoting search terms for which the redacted certificate should be served. This can be used to cache part of the identity string from a deleted userid, for example if a domain owner wishes to serve hard revocations in response to searches for their domain name, which would otherwise not be indexable. (see https://github.com/hockeypuck/hockeypuck/issues/338)
Keyservers configured with a list of enumerable domains will add to the primary key's quiet trust packet the domain portion of any userids that they delete due to a redacting signature. In turn, the indexer will treat these notations as additional search keywords.
Keyservers operated by the same person or organisation can be configured to add received identity cache entries if they were generated by a trusted peer, even if they do not match the current indexing policy. This should (😬) allow for updated indexing policies to be rolled out progressively without data loss.
Forbidden keys
Each forbidden key will have a record in the keys database containing a single noisy trust packet only. The trust packet's initial (hashed) subpacket contains the version-tagged fingerprint of the blocked primary key, and the packet context is 0.
This “key” will be synced like any other entry in the database, but will not automatically be added to the database of a receiving server. This will in general cause a persistent sync delta, but it should be remembered that blocklist differences already cause such deltas by design, and are handled by the LRU cache.
Keyservers operated by the same person or organisation can however be configured to add blocked key entries if they were generated by a trusted peer. In such cases the delta should eventually resolve.
This replaces the earlier “table blocklist” proposal mentioned in https://github.com/hockeypuck/hockeypuck/issues/184 and https://github.com/hockeypuck/hockeypuck/issues/229
Currently, "forbidden" keys are implemented by adding them to the blocklist in the configuration and then deleting them from the database. "Frozen" keys (i.e. the current behaviour when a key is added to the blocklist but not deleted from the database) could be implemented by adding a quiet trust packet on the primary key.
Out of scope
The inclusion of trust packets in HKP submissions and responses; these will be tackled separately if necessary.
Security considerations
TBC
Compatibility
Quiet trust packets should not cause compatibility issues with peers that correctly ignore foreign trust packets, since they will be discarded on import and existing servers should therefore not include them in the SKS hash. Noisy trust packets will require a filter bump to ensure they are hashed correctly on both sides.
Neither form of trust packet is intended to be exported to clients, however clients SHOULD ignore foreign trust packets and should therefore be unaffected if a keyserver were to accidentally serve them.
Plan
Quiet trust packets can be added at any time. Each distinct use of noisy trust packets will require a filter bump.