and "*optional*" to be interpreted as defined in [[https://tools.ietf.org/html/rfc2119][RFC 2119]].
The following terms have these definitions:
- *AP* means ActivityPub.
- *AS* means Activity Streams.
- *AS2* means Activity Streams 2.0.
- *AC* means Active Cryptography or Activity Cryptography; the
working title for the protocol extension.
The document also draws on the same RFCs cited by both the Activity
Streams [[https://www.w3.org/TR/activitystreams-core/][core]] and [[https://www.w3.org/TR/activitystreams-vocabulary/][vocabulary]] documents, as well as the [[https://www.w3.org/TR/activitypub/][ActivityPub]]
protocol definition.
* Cryptographic Activities
:PROPERTIES:
:CUSTOM_ID: crypto
:END:
This section introduces the new objects, collections, activity types
and properties necessary to implement OpenPGP functions with Activity
Streams 2.0 and ActivityPub.
** Cryptographic protocol
:PROPERTIES:
:CUSTOM_ID: crypto-protocol
:END:
In order to handle any situations in which servers and/or clients may
implement multiple cryptographic protocols, a property *must* be set
for any cryptographic object or activity.
#+begin_src javascript
{"cryptographic-protocol": "openpgp"}
#+end_src
Where the relevant JSON data is already clearly part of a
cryptographic object or activity this proprty *may* be defined as
=protocol=.
#+begin_src javascript
{"protocol": "openpgp"}
#+end_src
*** OpenPGP Protocol
:PROPERTIES:
:CUSTOM_ID: crypto-protocol-openpgp
:END:
When integrating OpenPGP with Activities or Objects, consideration
must be given to both the versions in use throughout the network and
setting sensible minimum requirements so as not to adversely affect
the rest of the network.
For this reason the current standards defined in RFC 4880 *must* be
implemented, while the recommendations of RFC 4880bis *should* be
available. Though a number of older versions of the standard *may* be
available with any given implementation, any older standard for which
existing recommendations state not to use them due to security related
issues then those older standards *must not* be used.
** MIME and file types
:PROPERTIES:
:CUSTOM_ID: crypto-mime-types
:END:
The media or content types utilised are adapted from the PGP/MIME
types defined in [[https://tools.ietf.org/html/rfc2015][RFC 2015]] and [[https://tools.ietf.org/html/rfc3156][RFC 3156]]. Specifically this covers the
=pgp-keys=, =application/pgp-encrypted= and =application/pgp-signed=
MIME types.
In addition to these an implementation *may* utilise
=application/pgp-encrypted+activitystreams= and *may* utilise
=application/pgp-signed+activitystreams= to indicate an Activity
Stream object (i.e. an =application/activity+json= object) is either
entirely affected by the cryptographic function or the object is
OpenPGP data which contains an ActivityPub or Activity Strams object
or activity type which will need to be processed upon decryption or
signature validation.
** Keys
:PROPERTIES:
:CUSTOM_ID: crypto-keys
:END:
Unlike the PEM key included with ActivityPub instances, OpenPGP keys
are always intended to be generated by the end user(s) controlling a
given actor's account and not controlled or accessed by the server,
even when that server is controlled by a single user.
There are also valid reasons or use cases for assigning multiple keys
to an actor or using the same key with multiple actors. This is
particularly the case if proof of OpenPGP key control was adopted as
an alternative means of providing authentication between a client and
server, in addition to OAuth methods.
Though there is already a well established network of public
keyservers, the SKS keyserver pool, and from GnuPG 2.1 there is the
[[https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/][OpenPGP Web Key Directory]] (WKD); there are also valid reasons for not
using these methods of providing access to a public key used with
activities.
Likewise, there is a need for serving key information with actor
information and referencing it with objects and activities where
necessary. This would effectively turn an ActivityPub instance into a
limited public keyserver for the keys assigned to actors under its
purview, though it may not maintain or serve copies of those keys
containing full web-of-trust signatures, particularly if there are
size constraints or bandwidth limitations.[fn:1]
*** Public keys and Actors
:PROPERTIES:
:CUSTOM_ID: crypto-actor
:END:
In order to enable access to cryptographic information controlled at
the user level we need to add an optional property to actors; one
where the absence of it equates to a value of =null=.
Since it is theoretically possible for multiple cryptographic
protocols to be in use, in addition to the Linked Data and HTTP
Signatures referenced in the ActivityPub specification, this optional
property *must* contain an array of JSON data listing the =protocol=
or =cryptographic-protocol=, the =cryptoContext= for a URI of a
collection containing more relevant data, the =publicKeys= for an
additional URI just for checking public key data and *may* contain a
=primaryKeyID= referencing the preferred key ID used with the actor.
Here is an example using the same actor example in the ActivityPub
specification. Note that the key ID or fingerprint used here does not
exist on the keyservers and is really just a SHA1 sum of the actor's
"keyblockASCII": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmDMEXCaxhxYJKwYBBAHaRw8BAQdAMSVyt57XCqdve8pvgC4BDkj+BYq6xKlsdMua\nIYiKl+y0SURhbmdlciBNb3VzZSAoU29jaWFsOiBAZG1Abm90LnNlY3JldC5leGFt\ncGxlLmNvbSkgPGRtQHNlY3JldC5leGFtcGxlLm5ldD6ImQQTFgoAQRYhBML6QP16\nLm3bek/fyxp0JaIlw+8fBQJcJrGHAhsDDAsKDQkMCAsHBAEDAgcVCgkICwMCBRYC\nAwEAAh4BAheAAAoJEBp0JaIlw+8fR0wBAOLXF7eYegcI4w21BsceE669hpwHBl6b\n5G5/dJQObkSkAP0Vdx7+CyIMJwAqDesQtnUKrxLp1TEsR3FWXmPO5fAvB7g4BFwm\nsgsSCisGAQQBl1UBBQEBB0AyMCTt0r9Gvth5whz4ED8znHo9KqR0AVjftlG86xe0\nLgMBCAeIeAQYFgoAIBYhBML6QP16Lm3bek/fyxp0JaIlw+8fBQJcJrILAhsMAAoJ\nEBp0JaIlw+8fRoQBANjV8BrkS0EzIcQpG8xgsfQESYGsj/B59h9QdL7eS6q5AP9V\nV/6JC2wBwzL38B4accNW/lNPDAMfS3LgqvQnAfgeDbgzBFwmsjUWCSsGAQQB2kcP\nAQEHQLiOaYOPCSEIc1SLk1dM/XbTr5+bIl1DPduKbl2aWsaTiO8EGBYKACAWIQTC\n+kD9ei5t23pP38sadCWiJcPvHwUCXCayNQIbAgCBCRAadCWiJcPvH3YgBBkWCgAd\nFiEEZd86OBTTutxefWj0jYfEQYNH8rsFAlwmsjUACgkQjYfEQYNH8rtiewEAp+wJ\nvMc3Qq8hv372nNVdzE7TySjvJpy05DmtPcbAZ4UBAMrpR6MadshSM7NZvlBAyhPl\n7YmogPQ2N28Ja3kX8l4GIMYBAKRzQtRVH+NlOA0tvPO2wcBYXJhSQF0k/S8EnzZu\nYMmwAP4h+e4ytRt5yUupjFRM+S4OY7rMRTAY0eeu8rJwBeLrAw==\n=0Eei\n-----END PGP PUBLIC KEY BLOCK-----\n"
}
]
}
]
}
#+END_SRC
Note the main =timestamp= is the date the key itself was last modified
and will usually match the timestamp of the last subkey to be added or
the timestamp of the most recent self-certification of a key. Whereas
the =lastUpdated= property notes the last time the copy of the public
key was updated on the server serving that data. Such an update
*should* normally be the result of a client uploading the key to the
actor account, but *may* be the result of the server refreshing key
data from the SKS keyserver network or the Web Key Directory service.
*** Serving Public Keys Via WebFinger
:PROPERTIES:
:CUSTOM_ID: crypto-keyserv-webfinger
:END:
An alternative approach to using the =openpgpkeys.json= file defined
in the previous section is to instead direct key retrieval traffic to
the existing [[https://webfinger.net/][WebFinger]] service utilised by ActivityPub and [[https://datatracker.ietf.org/doc/rfc7033/][defined]] in
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
* Footnotes
[fn:1] As a point of comparison, the author's current public key in
ASCII armored format with all the web-of-trust signatures included is
approximately 100KB in size, whereas the same key exported in its most
minimal and concise form is approximately 13KB. Most keys will be
smaller than that (the author's key is a 4Kb RSA certification and
signing primary key with a 3Kb RSA signing subkey, a 4Kb El-Gamal
encryption subkey and a 3Kb DSA2 signing subkey).
Note that a future draft of this protocol extension may shift the key
distribution method to utilise the proposed [[https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/?include_text=1][OpenPGP Web Key Directory]]
protocol; which would meet all the requirements of this protocol along
with very fine tuned user ID control with key distribution. At the
current time, however, adoption of the Web Key Directory service is
limited and its protocol design is not finalised.
[fn:2] As the example suggests, the example is heavily based on the
current state of the GnuPG Project. As this is a fictional thing
which may become real in the future, it's necessary to stress that
such a project *must* be both free and permissive in its licensing.
To choose only free (e.g. GPL and/or Affero GPL only) means to
sacrifice other people's security/lives for one's own political
beliefs, while to choose only permissive (e.g. BSD and/or Apache
and/or proprietary only) means to sacrifice other people's
security/lives for profit.
If any reading this have ever wondered why the GnuPG Project hasn't
moved away from its dual licensing under the GPLv2+ (free) and the
LGPLv2.1+ (permissive), this is why.
[fn:3] Since an actor contact email address may be different from any
of the user IDs listed on the public key, servers should be configured
with their own means of matching key IDs to email addresses. In GnuPG
this is what the =group= option is used for and various MUAs have
their own solutions (e.g. Enigmail's Per-Recipient Record and Mutt's
=crypt-hook=). It is also *recommended* that servers automatically
encrypt such notifications with the =trust model= set to /*always*/,
otherwise the server will need to be configured with its own key which
signs or locally signs all the keys uploaded by clients.
[fn:4] The session key for the encrypted message in this example is: