[git] gnupg-doc - branch, ben/w3c-as2, created. c8a74117ce7a28a4393aff79035405f497a35a24

by Ben McGinnes cvs at cvs.gnupg.org
Sat May 12 06:01:37 CEST 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GnuPG website and other docs".

The branch, ben/w3c-as2 has been created
        at  c8a74117ce7a28a4393aff79035405f497a35a24 (commit)

- Log -----------------------------------------------------------------
commit c8a74117ce7a28a4393aff79035405f497a35a24
Author: Ben McGinnes <ben at adversary.org>
Date:   Sat May 12 13:52:39 2018 +1000

    docs: OpenPGP over Activity Streams 2.0
    
    * First draft of the extension to W3C's Activity Streams 2.0 and
      ActivityPub protocols in the form emailed to the original W3C team
      members who developed those two protocols.
    * Putting it here because it should be added somewhere until a more
      permanent home is found for it and in the unlikely event I get hit
      by a bus it should still be of benefit to the world.

diff --git a/misc/w3c/as2/OpenPGPoverActivityStreams.org b/misc/w3c/as2/OpenPGPoverActivityStreams.org
new file mode 100644
index 0000000..dfaf9e0
--- /dev/null
+++ b/misc/w3c/as2/OpenPGPoverActivityStreams.org
@@ -0,0 +1,1266 @@
+#+TITLE: Active Cryptography: OpenPGP over Activity Streams 2.0
+#+STARTUP: showall
+#+LATEX_COMPILER: xelatex
+#+LATEX_CLASS: article
+#+LATEX_CLASS_OPTIONS: [12pt]
+#+LATEX_HEADER: \usepackage{xltxtra}
+#+LATEX_HEADER: \usepackage[margin=1in]{geometry}
+#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman}
+#+LATEX_HEADER: \author{Ben McGinnes <ben at gnupg.org>}
+
+
+* Introduction
+  :PROPERTIES:
+  :CUSTOM_ID: intro
+  :END:
+
+  | Version:        | 0.0.1-draft-001                          |
+  | Author:         | Ben McGinnes <ben at gnupg.org>             |
+  | Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D |
+  | Language:       | Australian English, British English      |
+  | xml:lang:       | en-AU, en-GB, en                         |
+
+  This document provides a specification for using OpenPGP
+  cryptography with the Activity Streams 2.0 transport method.  It was
+  devised with particular attention towards providing end-user
+  encryption and verification on federated ActivityPub based instances
+  (e.g. Mastodon and Pleroma).
+
+  This proposal is not an official part of the W3C's protocols, but is
+  offered as an optional means of addressing some of the security
+  issues identified as lacking or missing in those protocols.  As such
+  it is offered under the same terms as any [[https://www.ietf.org/][IETF]] or [[https://www.w3.org][W3 Consortium]]
+  standards or proposals as free for any use.  Example code, however,
+  may be released under the same terms as the GnuPG Project or some
+  other license as relevant.  Example code will be provided separately
+  from this document.
+
+
+** Motivation
+   :PROPERTIES:
+   :CUSTOM_ID: intro-motive
+   :END:
+
+   The current Presidential Administration in the USA has diverged
+   considerably from the policies of his predecessors with recent
+   legislative and regulatory changes which are set to enable a far
+   greater implementation of authoritarian policies and agendas, as
+   well as enabling those policies to be enforced beyond the territory
+   of the United States of America.  This sets a dangerous precedent
+   with regards to the freedom of all people around the globe to
+   communicate freely and privately, particularly when they may become
+   subject to matters which are entirely legal where they live, but
+   which the United States legislates against.
+
+   The legislative and regulatory changes in the United States of most
+   concern to the rest of the world at the present time are: the
+   removal of Net Neutrality provisions by the FCC, the CLOUD Act and
+   the SESTA/FOSTA Act.  The latter being the attempt to enforce
+   American laws regarding adult content, primarily of a sexual
+   nature, globally.  They also remove the “safe harbour” provisions
+   which previously permitted hosting providers to ignore what their
+   customers were doing, in turn making those providers tools of the
+   state who must police the actions of end users and actively censor
+   them.
+
+
+** Approach
+   :PROPERTIES:
+   :CUSTOM_ID: intro-approach
+   :END:
+
+   Over the course of the last decade or a little more, a great deal
+   of communication online has shifted towards using social media
+   networks.  Email is still good for many things, but it is not good
+   for everything and various types of social networks fill that need.
+
+   Modifying the underlying protocols or specifications of proprietary
+   networks, such as Twitter and Facebook, is generally not possible.
+   It is also clear that these networks will act against some or even
+   all of their own user base in order to achieve the goals of those
+   running the companies in question.
+
+   In the case of Facebook that is in the form of surveillance of
+   large populations and subsequent manipulation of them.  In the case
+   of Twitter it is in the form of banning those who vehemently oppose
+   Nazism or who discuss or promote adult entertainment of various
+   types, primarily pornography and sex work, regardless of the
+   jurisdiction to which the end user is actually subject.
+
+   Open standards and protocols, however, can be leveraged freely and
+   as necessary.  This is what Phil Zimmermann did back in 1991 when
+   he released the first version of Pretty Good Privacy for use with
+   Email, USENET and, very likely, FidoNet (or FidoNet style) BBS
+   networks.  The same approach may be utilised now with social
+   networks which themselves provide an open specification and where
+   that specification provides the means for extending or advancing
+   itself.
+
+   There is clearly grounds for social network users to have access to
+   the tools to send and receive end-to-end encrypted private messages
+   via their social network accounts and identities.  Likewise there
+   is a need for end users to be able to prove, should they wish to do
+   so, that a message was not modified in transit; either by their own
+   server of another within the federated networks in use.
+
+   This current proposal applies to the W3 Consortium's [[https://www.w3.org/TR/activitystreams-core/][Activity
+   Streams 2.0]] and [[https://www.w3.org/TR/activitypub/][ActivityPub]] protocols; the latter being based upon
+   the former.
+
+
+** Cryptographic Implementation Choice
+   :PROPERTIES:
+   :CUSTOM_ID: intro-crypto-choice
+   :END:
+
+   The cryptographic choice with regards to the GnuPG Project was
+   limited to the two engines which GnuPG currently supports: OpenPGP
+   and S/MIME.  Since the intended outcome of this proposal is to
+   provide a means of securing or preventing content manipulation to
+   end users directly, the OpenPGP model was selected.
+
+   It would, however, be possible to switch the security focus to the
+   server level in order to utilise S/MIME or some future advancement
+   may necessitate or simply favour utilising a different
+   cryptographic implementation or method.  As a consequence this
+   proposal is designed to more easily enable swapping one method for
+   another.
+
+   Note that this is separate and in addition to the use of a PEM key
+   by ActivityPub servers for each of their users.  In those cases the
+   private key is generated by the ActivityPub server when the user
+   account is created.  As a consequence it is inherently flawed from
+   a user security perspective.  It does, however, move the complexity
+   out of the user level and back to the server level.  Whereas this
+   proposal does not.
+
+
+** Definitions
+   :PROPERTIES:
+   :CUSTOM_ID: intro-definitions
+   :END:
+
+   *IMPORTANT:* Everything in this proposal is optional.  The
+   definitions listed here are within the context of the proposal
+   itself.
+
+   This document uses the terms defined in [[https://tools.ietf.org/html/rfc4880][RFC 4880]] and in the same
+   way.
+
+   The key words: "*must*", "*must not*", "*required*", "*shall*",
+   "*shall not*", "*should*", "*should not*", "*recommended*",
+   "*may*", 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
+
+
+** 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 GPG 2.1 there is an
+   alternative method of retrieving keys associated with a domain name
+   built-in; 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 =None= or
+    =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 name.
+
+    #+begin_src javascript
+      {
+	  "@context": ["https://www.w3.org/ns/activitystreams",
+		       {"@language": "ja"}],
+	  "type": "Person",
+	  "id": "https://kenzoishii.example.com/",
+	  "following": "https://kenzoishii.example.com/following.json",
+	  "followers": "https://kenzoishii.example.com/followers.json",
+	  "liked": "https://kenzoishii.example.com/liked.json",
+	  "inbox": "https://kenzoishii.example.com/inbox.json",
+	  "outbox": "https://kenzoishii.example.com/feed.json",
+	  "preferredUsername": "kenzoishii",
+	  "name": "石井健蔵",
+	  "summary": "この方はただの例です",
+	  "icon": [
+	      "https://kenzoishii.example.com/image/165987aklre4"
+	  ],
+	  "cryptoProtocols": [ {
+	      "protocol": "openpgp",
+	      "cryptoContext": "https://kenzoishii.example.com/openpgp.json",
+	      "publicKeys": "https://kenzoishii.example.com/openpgpkeys.json",
+	      "primaryKeyID": "3A1222F4BE79DB2AF069FADCF507B8E7E6EF68BF"
+	  }   ]
+      }
+    #+end_src
+
+    A slight variation demonstrating how multiple cryptographic
+    implementations could be utilised along with not specifying a
+    primary key ID may appear more like this:
+
+    #+begin_src javascript
+      {
+	  "@context": ["https://www.w3.org/ns/activitystreams",
+		       {"@language": "ja"}],
+	  "type": "Person",
+	  "id": "https://kenzoishii.example.com/",
+	  "following": "https://kenzoishii.example.com/following.json",
+	  "followers": "https://kenzoishii.example.com/followers.json",
+	  "liked": "https://kenzoishii.example.com/liked.json",
+	  "inbox": "https://kenzoishii.example.com/inbox.json",
+	  "outbox": "https://kenzoishii.example.com/feed.json",
+	  "preferredUsername": "kenzoishii",
+	  "name": "石井健蔵",
+	  "summary": "この方はただの例です",
+	  "icon": [
+	      "https://kenzoishii.example.com/image/165987aklre4"
+	  ],
+	  "cryptoProtocols": [ {
+	      "protocol": "openpgp",
+	      "cryptoContext": "https://kenzoishii.example.com/openpgp.json",
+	      "publicKeys": "https://kenzoishii.example.com/openpgpkeys.json",
+	      "primaryKeyID": "3A1222F4BE79DB2AF069FADCF507B8E7E6EF68BF"
+	  },
+	  {
+	      "protocol": "smime",
+	      "cryptoContext": "https://kenzoishii.example.com/smime.json",
+	      "publicKeys": "https://kenzoishii.example.com/smimekeys.json"
+	  }	]
+      }
+    #+end_src
+
+    As the example suggests, this would enable utilising both a client
+    controlled cryptographic method in the form of OpenPGP and a
+    server controlled or authorised cryptographic method in the form
+    of S/MIME.[fn:2]
+
+
+*** Cryptography Context
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-context
+    :END:
+
+    The cryptography contexts referenced from the actor define all the
+    ways in which any key or keys are used in relation to actions and
+    objects by or for that actor.  First by identifying the keys and
+    subkeys and then by defining which type of objects they're used in
+    relation to.  As well as whether the account is configured to
+    always use them, as *may* be the case with signatures or not.
+
+    The Cryptography Context is a collection of nested collections and
+    objects dealing with each key or subkey type and the ways they're
+    used in regards to activities or other objects.
+
+    In the following examples I use my current key in conjunction with
+    an imaginary (not-yet-existing) ActivityPub instance on my own
+    domain, =snuffy.adversary.org=.[fn:3]
+
+    The =keys= item *must* contain a =keyinfo= item for each public
+    key associated with the actor account.
+
+    The =keyinfo= item *must* contain =keyIDs= data for the primary key
+    and all enabled subkeys of the key.
+
+    The =keyinfo= item *must* contain a =type= property which
+    indicates both the key's cryptographic protocol and version number
+    of that protocol.  Most current OpenPGP keys are version 4 keys.
+
+    The =keyinfo= item *may* contain =keyIDs= data for /revoked/ or
+    /disabled/ keys previously used with the actor or revoked subkeys of
+    an active key.  Where this data is included the =keyID= item
+    *must* contain an =enabled= property with a boolean value of
+    /*True*/ or /*False*/.  Additionally a =revoked= property *may* be
+    included, also with a boolean value of /*True*/ or /*False*/.
+
+    Where the =enabled= and =revoked= properties are not included, the
+    default values are assumed to be that =enabled= is /*True*/ and
+    =revoked= is /*False*/.
+
+    The =keyinfo= item *may* contain =userIDs= data for some or all of
+    the userIDs listed on the key itself.
+
+    The =keyinfo= item *may* contain a =keyfiles= property with direct
+    links to either or both of the GPG or PGP binary key formats or
+    the ASCII armoured key file format.
+
+    The =keyinfo= item *must* contain the =publicKeys= property pointing
+    to a JSON encoded URL containing at least the minimised version of
+    the public key.
+
+    A =keyID= item *must* contain an =id= property of the full key ID
+    which is the hexadecimal key fingerprint without spaces.  The =id=
+    property *must not* be either the short or long key ID formats.
+
+    A =keyID= item *must* contain a =type= property with a value
+    indicating whether the key is the /*primary*/ (certification) key
+    or a /*subkey*/.
+
+    A =keyID= item *may* contain a =fingerprint= property with the
+    full key ID in a human readable format.  This is the finterprint
+    format which most OpenPGP users will be familiar with and normally
+    presents the fingerprint with spaces between hexadecimal groupings
+    of four characters each.
+
+    A =keyID= item *must* contain an =algorithm= property with a value
+    indicating which asymmetric cryptographic algorithm *or* which
+    elliptic curve algorithm it uses.
+
+    A =keyID= item *must* contain a =size= property with an integer
+    value of the bit size of the key or subkey.
+
+    A =keyID= item *must* contain properties for each of the four
+    capabilities a key or subkey may possess: =certification=,
+    =encryption=, =signing= and =authentication=.  The values for each
+    property are boolean strings; /*True*/ or /*False*/.
+
+    A =keyID= item *must* contain a =timestamp= property with an
+    integer value of the number of seconds since the epoch since the
+    key or subkey was last modified.  This will usually be the
+    timestamp of the key's creation, but may indicate some other
+    modification such as changing an expiration date or revoking the
+    key or subkey.
+
+    The remaining items address the three basic functions for which
+    OpenPGP keys can be used with Activity Streams: signing,
+    encryption and authentication.  In addition to those three
+    functions and policies, additional use case policies *may* be
+    appended: refreshing a key from the keyservers, encrypting email
+    notifications regarding activities to the relevant email address
+    for the actor account.[fn:4]
+
+    Each of these items *must* include a =policy= property which
+    stipulates whether or not that function is available and the
+    consistency of that use.  Possible policy values are /*must*/,
+    /*may*/ and /*never*/.  Recommended default values are /*may*/
+    unless the relevant key or subkey type is unavailable, in which
+    case the correct value is /*never*/.
+
+    If the policy value for an item is either /*must*/ or /*may*/ then
+    the =authorizedKeyIDs= property *must* include an array with all
+    full key IDs of the primary key and relevant subkeys to perform
+    that task.  If the policy value is /*never*/ then the
+    =authorizedKeyIDs= *may* be =None= or =null=.
+
+    #+begin_src javascript
+      {
+	  "@context": "https://www.w3.org/ns/activitystreams",
+	  "id": "https://snuffy.adversary.org/openpgp.json",
+	  "summary": "OpenPGP use and keys with this stream",
+	  "type": "openpgpCollection",
+	  "cryptographic-protocol": "openpgp",
+	  "totalItems": 6,
+	  "items": [
+	      {
+		  "type": "openpgpKeys",
+		  "totalItems": 1,
+		  "items": [
+		      {
+			  "id": "keyinfo",
+			  "type": "openpgpKeyV4",
+			  "timestamp": 1514332912,
+			  "lastUpdated": 1524951377,
+			  "keyIDs": [
+			      {
+				  "id": "DB4724E6FA4286C92B4E55C4321E4E2373590E5D",
+				  "type": "primary",
+				  "fingerprint": "DB47 24E6 FA42 86C9 2B4E  55C4 321E 4E23 7359 0E5D",
+				  "algorithm": "RSA",
+				  "size": 4096,
+				  "certification": True,
+				  "signing": True,
+				  "encryption": False,
+				  "Authentication": False,
+				  "timestamp": 1343480251
+			      },
+			      {
+				  "id": "B7F0FE759387430DD0C58BDB7FF2D37135C7553C",
+				  "type": "subkey",
+				  "fingerprint": "B7F0 FE75 9387 430D D0C5  8BDB 7FF2 D371 35C7 553C",
+				  "algorithm": "RSA",
+				  "size": 3072,
+				  "certification": False,
+				  "signing": True,
+				  "encryption": False,
+				  "Authentication": False,
+				  "timestamp": 1343480419
+			      },
+			      {
+				  "id": "9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D",
+				  "type": "subkey",
+				  "fingerprint": "9CBE F6B7 E0DF 72CF 9100  9AA5 C98B AA18 62E4 484D",
+				  "algorithm": "ELG",
+				  "size": 4096,
+				  "certification": False,
+				  "signing": False,
+				  "encryption": True,
+				  "Authentication": False,
+				  "timestamp": 1343480559
+			      },
+			      {
+				  "id": "A48B28F39A83E63C55B8F30E48723A7579041EC6",
+				  "type": "subkey",
+				  "fingerprint": "A48B 28F3 9A83 E63C 55B8  F30E 4872 3A75 7904 1EC6",
+				  "algorithm": "DSA",
+				  "size": 3072,
+				  "certification": False,
+				  "signing": True,
+				  "encryption": False,
+				  "Authentication": False
+				  "timestamp": 1514332912
+			      }
+			  ],
+			  "userIDs": [
+			      {
+				  "name": "Ben McGinnes",
+				  "comment": None,
+				  "email": "ben#adversary.org"
+			      },
+			      {
+				  "name": "Ben McGinnes",
+				  "comment": None,
+				  "email": "ben#gnupg.org"
+			      }
+			  ],
+			  "keyfiles": [
+			      {
+				  "url": "http://www.adversary.org/ben-key.asc",
+				  "Content-Type", "application/pgp-signature",
+				  "summary": "ASCII armored openpgp keyfile, full key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key.gpg",
+				  "Content-Type", "application/pgp-keys",
+				  "summary": "Binary openpgp keyfile, full key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-clean.asc",
+				  "Content-Type", "application/pgp-signature",
+				  "summary": "ASCII armored openpgp keyfile, clean key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-clean.gpg",
+				  "Content-Type", "application/pgp-keys",
+				  "summary": "Binary openpgp keyfile, clean key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-min.asc",
+				  "Content-Type", "application/pgp-signature",
+				  "summary": "ASCII armored openpgp keyfile, minimised key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-min.gpg",
+				  "Content-Type", "application/pgp-keys",
+				  "summary": "Binary openpgp keyfile, minimised key"
+			      }   ],
+			  "publicKeys": "https://snuffy.adversary.org/openpgpkeys.json"
+		      }
+		  ]
+	      },
+	      {
+		  "type": "content-signing",
+		  "policy": "May",
+		  "authorizedKeyIDs": [ "DB4724E6FA4286C92B4E55C4321E4E2373590E5D",
+					"B7F0FE759387430DD0C58BDB7FF2D37135C7553C",
+					"A48B28F39A83E63C55B8F30E48723A7579041EC6" ]
+	      },
+	      {
+		  "type": "encryption",
+		  "policy": "May",
+		  "authorizedKeyIDs": [ "DB4724E6FA4286C92B4E55C4321E4E2373590E5D",
+					"9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D" ]
+	      },
+	      {
+		  "type": "authentication",
+		  "policy": "Never",
+		  "authorizedKeyIDs": None
+	      },
+	      {
+		  "type": "refresh"
+		  "policy": "May",
+		  "authorizedKeyIDs": [ "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" ]
+	      },
+	      {
+		  "type": "email-encryption",
+		  "policy": "Must",
+		  "authorizedKeyIDs": [ "DB4724E6FA4286C92B4E55C4321E4E2373590E5D",
+					"9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D" ]
+	      }
+	  ]
+      }
+    #+end_src
+
+    There are numerous ways in which OpenPGP may be leveraged by a
+    server to provide authentication mechanisms for an actor utilising
+    either signatures, encrypted tokens to be decrypted and used like
+    OAuth or even using the authentication subkey type in a manner
+    similar to TLS or SSH.  For this example these possibilities are
+    disregarded in order to demonstrate how a policy may be set to not
+    use one possible function.
+
+    A server might also use the public keys in a more traditional
+    manner for OpenPGP and certain other cryptographic implementations
+    (e.g. S/MIME) if end users receive email notifications of
+    activites.  In that circumstance the server could, if the public
+    key had a subkey with the encryption capability and the relevant
+    matching policy, encrypt those emailed notifications.
+
+    Also note that while default and recommended key generation
+    stipulates that OpenPGP primary (certification) keys *should not*
+    have the encryption capability, it is still advisable to include
+    that primary key ID as authorized for any function granted to any
+    of its subkeys.  The reason being that not every OpenPGP
+    implementation correctly interprets the relationship between the
+    primary key and those subkeys (e.g. some of the JavaScript
+    implementations).  By explicitly including the primary as
+    authorized, even for those tasks for which it does not have the
+    capability we avoid unnecessary false error reports with certain
+    OpenPGP implementations.
+
+    If an actor has multiple keys assigned to it, it *should* be
+    permitted to extend the policy section to provide for different
+    policies for each key.
+
+    For instance it may be preferred to have one main key which is
+    always refreshed from the keyservers, but a backup key which is
+    only updated manually by an end user.  The following example
+    demonstrates how a single type can be expanded to cover multiple
+    policies.  Where there is only one policy, as in the larger
+    example above it is assumed that the =policies= property has a
+    value of =1= and *may* be omitted.
+
+    #+begin_src javascript
+      {
+	  "type": "email-encryption",
+	  "policies": 2,
+	  {
+	      "policy": "Must",
+	      "authorizedKeyIDs": [ "DB4724E6FA4286C92B4E55C4321E4E2373590E5D",
+				    "9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D" ]
+	  },
+	  {
+	      "policy": "May":
+	      "authorizedKeyIDs": [ "6468C3737B7B3F396827EC15371AC5BFA04AE313",
+				    "BA212621459C5135409D5F5DDE7D158D34DF2F7F" ]
+	  }
+      }
+    #+end_src
+
+
+*** Serving Public Keys
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-keyserving
+    :END:
+
+    The =openpgpKeys.json= file contains a lot of matching data to the
+    main context file by necessity since both need to include the key
+    ID data and both will usually include someuser ID data.  Both of
+    which being data about the public key which is available from the
+    public key itself.  The main differences, however, are that the
+    context file provides the information on the circumstances under
+    which the public key either can, should or must be used; but does
+    not include a copy of the public key itself.  While the other file
+    only has data about the key itself and a copy of at least the
+    minimised key (or keys if there are multiple keys assigned to an
+    actor or stream).
+
+    #+begin_src javascript
+      {
+	  "@context": "https://www.w3.org/ns/activitystreams",
+	  "id": "https://snuffy.adversary.org/openpgpkeys.json",
+	  "stream": "https://snuffy.adversary.org/",
+	  "summary": "OpenPGP public keys for this stream.",
+	  "type": "openpgpKeys",
+	  "cryptographic-protocol": "openpgp",
+	  "totalItems": 1,
+	  "items": [
+	      {
+		  "type": "openpgpKey",
+		  "keyVersion": 4,
+		  "totalItems": 2,
+		  "lastUpdated": 1524951377,
+		  "items": [
+		      {
+			  "type": "openpgpKeyData",
+			  "timestamp": 1514332912,
+			  "keyIDs": [
+			      {
+				  "id": "DB4724E6FA4286C92B4E55C4321E4E2373590E5D",
+				  "type": "primary",
+				  "fingerprint": "DB47 24E6 FA42 86C9 2B4E  55C4 321E 4E23 7359 0E5D",
+				  "cipher": "RSA",
+				  "size": 4096,
+				  "certification": True,
+				  "signing": True,
+				  "encryption": False,
+				  "Authentication": False,
+				  "timestamp": 1343480251
+			      },
+			      {
+				  "id": "B7F0FE759387430DD0C58BDB7FF2D37135C7553C",
+				  "type": "subkey",
+				  "fingerprint": "B7F0 FE75 9387 430D D0C5  8BDB 7FF2 D371 35C7 553C",
+				  "cipher": "RSA",
+				  "size": 3072,
+				  "certification": False,
+				  "signing": True,
+				  "encryption": False,
+				  "Authentication": False,
+				  "timestamp": 1343480419
+			      },
+			      {
+				  "id": "9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D",
+				  "type": "subkey",
+				  "fingerprint": "9CBE F6B7 E0DF 72CF 9100  9AA5 C98B AA18 62E4 484D",
+				  "cipher": "ELG",
+				  "size": 4096,
+				  "certification": False,
+				  "signing": False,
+				  "encryption": True,
+				  "Authentication": False,
+				  "timestamp": 1343480559
+			      },
+			      {
+				  "id": "A48B28F39A83E63C55B8F30E48723A7579041EC6",
+				  "type": "subkey",
+				  "fingerprint": "A48B 28F3 9A83 E63C 55B8  F30E 4872 3A75 7904 1EC6",
+				  "cipher": "DSA",
+				  "size": 3072,
+				  "certification": False,
+				  "signing": True,
+				  "encryption": False,
+				  "Authentication": False,
+				  "timestamp": 1514332912
+			      }   ],
+			  "userIDs": [
+			      {
+				  "name": "Ben McGinnes",
+				  "comment": None,
+				  "email": "ben#adversary.org"
+			      },
+			      {
+				  "name": "Ben McGinnes",
+				  "comment": None,
+				  "email": "ben#gnupg.org"
+			      }   ],
+			  "keyfiles": [
+			      {
+				  "url": "http://www.adversary.org/ben-key.asc",
+				  "Content-Type", "application/pgp-signature",
+				  "summary": "ASCII armored openpgp keyfile, full key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key.gpg",
+				  "Content-Type", "application/pgp-keys",
+				  "summary": "Binary openpgp keyfile, full key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-clean.asc",
+				  "Content-Type", "application/pgp-signature",
+				  "summary": "ASCII armored openpgp keyfile, clean key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-clean.gpg",
+				  "Content-Type", "application/pgp-keys",
+				  "summary": "Binary openpgp keyfile, clean key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-min.asc",
+				  "Content-Type", "application/pgp-signature",
+				  "summary": "ASCII armored openpgp keyfile, minimised key"
+			      },
+			      {
+				  "url": "http://www.adversary.org/ben-key-min.gpg",
+				  "Content-Type", "application/pgp-keys",
+				  "summary": "Binary openpgp keyfile, minimised key"
+			      }   ]
+		      },
+		      {
+			  "keyblockASCII": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFAT4bsBEADDsKVDXPxbY88oDXwoNeTQ6KaKxxZ9fE2PGv3dtUBqCX8opuVz\nLaJ19UBuTjiFdgqY+jx2hYBKl026q2btg7Ijhcstbu3HZ3NzxDGk2JGFMUe0WHxC\ndLSf5MuFbCFu17zwCmkT1my9Fcb++0UkwCFnVaKzXB1oS8gnl1Hjr3jbmH8LhUAi\nYXfSIZPbLb+LGxVhEKldUBVlmjbDvbiMFe2c+X2nixA64Vtaqo4q6D78401CQXns\nZ8Z4lA9pXj6sB/4d+zFLtyvSmsq0ccTbmwmw0kk5FYnM7Gn75kCviXQZyT5wt2EE\nDv7zwRgs9Ih009Y4+xyrCt/ks34sWTPFDXhys7h9E0ujCJ65pxOl9pRXo1Mii6SF\n/0a5gHQZwaZ+a2wMoMD7tWw9d1OFNEOKAxv8ZY4Kk4kFp/Nq2Rb9wIVLY8TQhX34\nn9zIEnRwt/BiC9xo/2U+FxKrWTvZieJDNsrETnmRRcwWsfp16RBFUNe6bakSkxZ3\nqbVZesg1qExB9xbfzm00/c4mWr40wfE/UZsJnszzmNUBVtKCJJT5SmwP3xrHAssS\n0SeGhRwqJ+sUCfyjvo8zHCIkRS5CDiJ9Mc8rN3vSJuAf6dxr3NrExrRuMTpO0zaq\n2JPz4CF1Efu1YoggDhSltliRTw+Nhy7JxsIMKWLRimtfjxXDVH18plJ0bQARAQAB\ntCBCZW4gTWNHaW5uZXMgPGJlbkBhZHZlcnNhcnkub3JnPokCfwQTAQoAaQIbAwIe\nAQIXgAIZAQwLCg0JDAgLBwQBAwIHFQoJCAsDAgUWAgMBABYhBNtHJOb6QobJK05V\nxDIeTiNzWQ5dBQJaOjS/JBhoa3BzOi8vaGtwcy5wb29sLnNrcy1rZXlzZXJ2ZXJz\nLm5ldAAKCRAyHk4jc1kOXa/YD/9qnQOd39KlR035Gm9g1lOCCpjiVctZ225LipKb\nPUNtH6aXo4QkFuVaGdkKdHd4YUiAlxD0BGe7WVj8wnRrS0uo4Nt8+wqFmkalXRu/\nExIFuJqPN/UxQpxnQxZRNraohBX4/q/G6OcOcR24lvinbckpaA5cLaaahcaXQgy/\nzGh9vpv15ldbIlFcony4B/cIxBYm9H4AgF4/tl1CK4uC4t7ZeuctXjyPt0XM+fdN\nK9X4xr+Q5LZ+Z8QWMDEzaxLSiZoUxehdlGQprELQDSngjP8PoKcgXzjA9mCxQ7zN\nCuoq+R1OV7fPmtgJxkw5LWvS4CEiIeh37epfBxz0tu0U1iy+Swgzx1cD39ENVoqI\nkaddAy09Vfr8BYWkMFBsLnA7FMCJineaDZV9bu2vBCeGT3zsb5lLUWcJoFqE2gtl\nBKCVBTniMcSCb0O5ztT4R0E/BUfYlVkAJYRUTCytYmilp9Vx6VckFRqECzB34OyD\n3hLCeof/uy4lmU0WSi0bkPgFvyF0jSZvPDwfqPRN9jGRamul9j9UJXgQZWEXsmOr\n/8Lh+Mwhzm5Y3pLns8us8cpEZAl2ykz/aPHYVJ9CvI0a4V9dsil3wod+Ll7iaZHP\nR8CPQHsGDVW7/8tyK2NvXfOhjbnYKWeV7UHrjsd8NmL5UmniwDW/GUnrGGz5z9Ky\nVxq1QrQ7QmVuIE1jR2lubmVzIChiYWNrdXAgZW1haWwgYWRkcmVzcykgPGJlbm1j\nZ2lubmVzQGdtYWlsLmNvbT6JAnwEEwEKAGYCGwMCHgECF4AMCwoNCQwICwcEAQMC\nBxUKCQgLAwIFFgIDAQAWIQTbRyTm+kKGyStOVcQyHk4jc1kOXQUCWjo1HSQYaGtw\nczovL2lwdjQucG9vbC5za3Mta2V5c2VydmVycy5uZXQACgkQMh5OI3NZDl2U6w/8\nDOc2qm3aXr/vcdsLVRTS0cpN9Mz0EOiQVsFqfLHUo90kAUCfVxJu51qILpm7oXwf\nR+MXOSNqLMNQt6/PTjUMedWttVWlHVQTtyRwNSrY+5h2OBJln+VCcatIDLt97pgH\nkeih/PCHFuhOoy08YUutLnara1aSXEQqqvGZcYsZPc1znLgludkIUyfyhbu7umB6\n5BkPEgomBpNUqZ6Z5NNrqQNflI5yNCe0yN93Qfja7YBPafk1OXjumjIP3SjGo9+Z\nkre4A6i88DAxmZQLNsTD4aoqrm5S2NfnoqZXIiJqfAwj+n/LhaT3J8VjheUeOJVx\nMCEzgKaHLTMK0ClcTIpajsPqklBEGzgL8bgU79hbZCOXM7wEz9Kz8YEN2PrblaXp\n5/MfZoTHejfZuwZ1GcsbMCyTumbhLqbwpyHQADPbpgx+gcV587Wty4RzZglIbMu6\nK7r5z6PN32df6chXBS2tdFk2uH8JKHY2eMhCdxZPsPVJn9mOF7EoXLmmpjMqynmj\nsLHD3fFgcZn4DPRoczU+6jfbB29QUsd++plY0j3zhr5iE/+KCwFiDUK3qMgXBbbE\nWSSgnj08AognfdZCslsWrr54WsUD2X5twwfV9iR7JQMs7bq0vfo5zpBTNuskk7N/\nY8gQ/560t4kMdDqIeFtT8cauWcbD6HNfLPF1ara6vrm0LkJlbiBNY0dpbm5lcyA8\nYmVuLm1jZ2lubmVzQHBpcmF0ZXBhcnR5Lm9yZy5hdT6JAnYEEwEKAGACGwMCHgEC\nF4AMCwoNCQwICwcEAQMCBxUKCQgLAwIFFgIDAQAWIQTbRyTm+kKGyStOVcQyHk4j\nc1kOXQUCWjo1WB4YaGtwOi8vcG9vbC5za3Mta2V5c2VydmVycy5uZXQACgkQMh5O\nI3NZDl2qKRAAiZAwfN1WNzx6P9Ts5jtSCt+3zGohZftQ382C5quud6NCKuO9//ql\nuepriQk+5TJ58nXgz8T6BUzDGTTAVh26czsVKw7CEqPHD1psOSFUZV7nW13Z3YJO\ng3oKelg1LfSSKCYlWS1K7eBCT/2Uo/NV/yQfNqLoFYmxQX7u0fzTyLvCfBC6NIrf\nYCQTS77NP3lKpDLLkIyh9pKcOttljKv7uxz1Bpf3ozpfbSKVJaOgm/F8qQQkmtXy\nbu/8N5k5VJCodPFyU7HOiouzUv1hFQeqyZRsdgOILWJbC2r5Y57mMEshgfdBebwU\nYqyjvtRq9DKumQMJwTTGYshqEIgugUpBcqDfl1ZIDtQWyGkr96q5FP6z+48/pFa5\nOEQdFwjL5OPBLOJVLeKoj05XpG5JPPkgxHoQAw+FDZDXN22QYjeZmpOQi4kXb9DK\nAPHnAMk6aDFdVHzPtN/15+jByvhGVb4XttMVhbpOrUwrGOgVaVFVoi/w8mufkF8c\niCCYRSDzJJlC99XLqclISmuhMypzTpEFI5IIConC5oznicXLa8hY8O09HGx0dTr/\nOeteQOg423XIHf0XoERshtZcoACsszQYWGrGG6WCxz9js14VLevfinpSxlTk0MI/\njSuv8ZQACiNO3aDqTo8nzjGR1vATP3lxoJobDdHwCZ9D/0LNFIECDCO0KUJlbiBN\nY0dpbm5lcyA8YmVuLm1jZ2lubmVzQHBpcmF0ZS5vcmcuYXU+iQJbBDABCABFBQJX\naN76Ph0gcGlyYXRlLm9yZy5hdSBubyBsb25nZXIgZm9yd2FyZHMgbWFpbCB0byBw\naXJhdGVwYXJ0eS5vcmcuYXUuAAoJEDIeTiNzWQ5dxKAP/A5KmG+O6g+HK/tCkR3x\ntdLTKwUtF4LGmexzI00cHTNWrrPXKGIsxZM+Bf4+YDls6VhwJFTJBddoE+8WIw4C\nQdtxJp151xkqsZxInjS99ch9OylqcjXTKvHC3myX/cYWnSAXTbS31SgPruUZX5sk\nLTqcd+GfT1S8OzQRwGtPfWVRwvR6IyhoJKG8j6o+OPFfvqEJSTzHkOMYn5pYY6Ji\nIZktthrnKCvStSGNn9QArBKLtZKDuDHHq+dpu8fZngtnrMigwn4a3Sak0lVKh+CU\nUkBPxLzMJYB/4ecKBIGSyY+0NHzEJ58zzNFgk9M/xjhcVzbrzDnBtphtJGeJszu9\nPtwmQIvLbIwa/uDYXKWWYnSE2hMslyGSV0qe/5aOF29PAUXybhy+Bp1iHAjYCMJ7\nGTC8p48wCBVBImyW9DZrZsCAnazewbEZa7mPeUyUpvio+BfGSDm8LnmdzpkMTZi0\nEA+06qvFCOx2IXDBm1Q+HKfsiq4ft5cnCcKNAu5YtKELoh3dT9+smhMJYkqpJJqK\nUWdQZu1abxFok9W4hHEBQHYbBZlVfZydOeCRZs4tqMHxQk3kFYJtalWWnUrfJaG5\nIDrEPju4T5njOh98S3aRwlFCtUDz94rinRRAzgK5+8nB84lkUNrm6VE/nNa5RkC6\nAY0mAyooRF89BpFbHVTJE3REtCtrZXliYXNlLmlvL2FkdmVyc2FyeSA8YWR2ZXJz\nYXJ5QGtleWJhc2UuaW8+iQJ8BBMBCgBmAhsDAh4BAheADAsKDQkMCAsHBAEDAgcV\nCgkICwMCBRYCAwEAFiEE20ck5vpChskrTlXEMh5OI3NZDl0FAlo6NX0kGGh0dHA6\nLy9pcHY0LnBvb2wuc2tzLWtleXNlcnZlcnMubmV0AAoJEDIeTiNzWQ5d1YwP/1CR\nc8GFMNyu3wypeUW/+DTzEhUigtdHx1e+XO+CkouhIHbXHlIoIZjuKOxoaAxaCXo3\nW24HE4N9BCp7NE2aJ2vIWnvzNiv1YDxBnUx/+kUzuLIUSVGNjqhN+bV8MZ4uix+m\nc3WaN36BX6FF7lzavQ6C54cijl0HRc77Scyw/OdlOBtviNCB6Lr7hBHMIEyCUn5E\n4fIyZz1SZDzL9ZZL2IUhSFZAmm6Ff6yqd0uQVLmXyS++lGpuWrIPxtYGPWA0W8GQ\nmQUrOn8EhPz/Z2oVMoAcZfEElRXftf96FG+kCps+WVpSgixzrZIgTQMVDB1SqQRC\n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\nuQ==\n=P42o\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.
+
+
+** Signatures
+   :PROPERTIES:
+   :CUSTOM_ID: crypto-signing
+   :END:
+
+   Signing activities as a means of providing assurance that they
+   genuinely originate with the client and have not been modified in
+   transi will most likely be one of the most common uses of these
+   functions.
+
+   There are, however, issues with possibility that a server may
+   render the content differently to the author's system or sanitize
+   the content in an unexpected manner.  Also the author might use
+   another content format (e.g. Markdown) which is intended to be
+   rendered into HTML by the server.
+
+   The solution to this problem is a new object type, the Signed
+   Note.
+
+   A Signed Note *must* contain a =source= property containing the
+   original data transmitted, even if the mediaType is =text/html= as
+   the server may still render it differently.
+
+   A Signed Note *must* contain a =signatures= property which *must*
+   specify the protocol and *must* include a detached signature file
+   for the source data.
+
+   The =scope= property specifies which source properties were signed,
+   usually this should only be the subject and content or just the
+   content.
+
+   The =signatures= property *may* include a signature for the
+   expected rendered output.  As with the source signature, the
+   =scope= property specifies which rendered output properties were
+   signed.
+
+   Since the order will matter with regards to the =scope= a
+   =signedData= property must be included with with each signature.
+
+   This is followed by the detached =signature= in ASCII armoured
+   (radix64) format and some additional data pertaining to the key or
+   subkey used to sign the data as =signingKeyID=, the algorithms used
+   as the =pubkeyAlgorithm= and the digital =hashAlgorithm=, and the
+   =timestamp= of the signature.
+
+   It *should* be possible for anyone with the Signed Note object to
+   take the signedData and the detached signature, save them both to
+   files and then manually verify them with OpenPGP compliant software
+   (e.g. =gpg=, or =gpg.exe=).
+
+   #+begin_src javascript
+     {
+	 "@context": ["https://www.w3.org/ns/activitystreams",
+		      { "@language": "en" } ],
+	 "type": "Signed Note",
+	 "id": "http://snuffy.adversary.org/posted/thing",
+	 "subject": "GnuPG rocks",
+	 "content": "<p>So, what <em>should</em> be signed, what was written or what was rendered?</p>",
+	 "source": {
+	     "subject": "GnuPG rocks",
+	     "content": "So, what *should* be signed, what was written or what was rendered?",
+	     "mediaType": "text/markdown"
+	 },
+	 "signatures": {
+	     "cryptographic-protocol": "openpgp",
+	     { 
+		 "scope": { "source": ["subject", "content"] },
+		 "signedData": "GnuPG rocksSo, what *should* be signed, what was written or what was rendered?",
+		 "signature": "-----BEGIN PGP SIGNATURE-----\n\niHUEABEKAB0WIQSkiyjzmoPmPFW48w5Icjp1eQQexgUCWuVpjAAKCRBIcjp1eQQe\nxhXcAP0e5qTuD4wO+fyL+0djvoAmZtPAzg4zyf5Tn5dZZVzOhAEA4B1I7ApWHpTr\nIJ0SwT/wy0vc5guSt/gru7SLANnBZGI=\n=fwud\n-----END PGP SIGNATURE-----\n",
+		 "signingKeyID": "A48B28F39A83E63C55B8F30E48723A7579041EC6",
+		 "pubkeyAlgorithm": "DSA",
+		 "hashAlgorithm": "SHA512",
+		 "timestamp": 1524984204
+	     },
+	     { 
+		 "scope": { "expectedRender": ["subject", "content"] },
+		 "signedData": "GnuPG rocks<p>So, what <em>should</em> be signed, what was written or what was rendered?</p>",
+		 "signature": "-----BEGIN PGP SIGNATURE-----\n\niHUEABEKAB0WIQSkiyjzmoPmPFW48w5Icjp1eQQexgUCWuVsKQAKCRBIcjp1eQQe\nxoYFAP4oOZSYXTAKd673B4PqZQp47kdYxRUfR7tdKBh8qV2YVgEA8m+/foWZO9xy\nm9v3zzeI/BYpGCeKZ7eqe29exQpvKds=\n=FDKU\n-----END PGP SIGNATURE-----\n",
+		 "signingKeyID": "A48B28F39A83E63C55B8F30E48723A7579041EC6",
+		 "pubkeyAlgorithm": "DSA",
+		 "hashAlgorithm": "SHA512",
+		 "timestamp": 1524984204
+	     }
+	 }
+     }
+   #+end_src
+
+
+** Encryption
+   :PROPERTIES:
+   :CUSTOM_ID: crypto-encryption
+   :END:
+
+   Encrypting activity content or content and subjects will meet the
+   needs of many feature requests on numerous instances.  There are,
+   however, some variations of methods which may be worth examining,
+   along with issues pertaining to availability of metadata and what
+   options, if any, exist for providing any measure of forward
+   secrecy.
+
+   There are multiple issues to be addressed when dealing with
+   encrypted activities, objects or portions of either.  Some of these
+   issues relate to whether the ciphertext contains additional
+   embedded JSON data to be interpreted or rendered by the recipient
+   upon decryption, while others relate more to the addressing or
+   total number of recipients or how to treat data when not all the
+   intended recipients have a public ky available.
+
+   Still, one problem it readily solves is in providing end-to-end
+   encrypted messages between two single actors.
+
+
+*** Encrypted Private Messages
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-encryption-privmsg
+    :END:
+
+    There are essentially two methods of sending an encrypted private
+    message: one in which the encrypted content is just the message
+    being sent, which *may* contain content or markup intended to be
+    parsed or rendered at the recipient's end; and the other being
+    when the encrypted content contains embedded JSON data matching
+    the Activity Streams 2.0 specification and possibly the
+    ActivityPub specificationto be interpreted by software at the
+    recipient's end.
+
+    Regardless of which it is, the sending of it requires another new
+    AP object, the Encrypted Note.
+
+    The Encrypted Note *must* contain an =encrypted= property.
+
+    Thw =encrypted= property *may* contain a =subject= property.
+
+    Thw =encrypted= property *must* contain a =content= property in
+    which then encrypted data is inserted in radix64 ASCII armoured
+    format.
+
+    Thw =encrypted= property *should* contain a =mediaType= property
+    with a value of =application/pgp-encrypted= or
+    =application/pgp-encrypted+activitystreams=.
+
+    Thw =encrypted= property *may* contain a =signingKeyID= property
+    containing the =id= of the key used to sign the encrypted content,
+    if any.  Alternatively the =signingKeyID= property *may* be an
+    array of multiple keys or subkeys if more than one key was used to
+    sign the data.
+
+    Thw =encrypted= property *may* contain a =recipientKeyIDs=
+    property containing an array of the key IDs to which the encrypted
+    data has been encrypted.  If the recipients have been hidden then
+    the =recipientKeyIDs= property *may* be excluded or explicitly set
+    to either =None=, =null=, or /*Hidden*/.
+
+    Thw =encrypted= property *must* contain a =cipher= property with a
+    value of the symmetric cipher used to encrypt the =content= data.
+
+    Thw =encrypted= property *must* contain an =encryptedAlgorithm=
+    property containing a value of the asymmetric encryption or
+    elliptic curve algorithms of the =recipientKeyIDs=.  If there
+    multiple algorithms then this data *must* be included in an
+    array.  This requirement remains even if the =recipientKeyIDs=
+    property is =None=, =null= or /*Hidden*/.
+
+    Thw =encrypted= property *may* contain a =hash= property with a
+    value of the hash digest algorithm used to sign the =content=
+    data, if any.
+
+    Thw =encrypted= property *may* contain a =signingAlgorithm=
+    property with a value of the digital signature algorithm of the
+    key used to sign the =content= data.  If multiple keys were used
+    to sign the data and those keys used different signing algorithms
+    then this *may* be an array containing each algorithm.
+
+    Thw =encrypted= property *should* contain a =timestamp=, except
+    where enough of the data regarding the encrypted =content= does
+    not include an actual timestamp.
+
+    The following example is about as simple as it gets.  The
+    =content= is encrypted and signed, in this case simply containing
+    a small Markdown text file.[fn:5]
+
+    #+begin_src javascript
+      {
+	  "@context": ["https://www.w3.org/ns/activitystreams",
+		       { "@language": "en-AU" } ],
+	  "type": "Encrypted Note",
+	  "id": "http://snuffy.adversary.org/posted/encrypted-thing",
+	  "to": "http://snuffy.adversary.org/inbox",
+	  "subject": "Secret Message",
+	  "cryptographic-protocol": "openpgp",
+	  "encrypted": {
+	      "subject": "Secret Message",
+	      "content": "-----BEGIN PGP MESSAGE-----\n\n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\nBzIvDuNDNcYV\n=elBL\n-----END PGP MESSAGE-----\n",
+	      "mediaType": "application/pgp-encrypted",
+	      "signingKeyID": "A48B28F39A83E63C55B8F30E48723A7579041EC6",
+	      "recipientKeyIDs": [ "9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D" ],
+	      "cipher": "TWOFISH",
+	      "encryptionAlgorithm": "ELG",
+	      "hash": "SHA512",
+	      "signingAlgorithm": "DSA",
+	      "timestamp": 1524996957
+	  }
+      }
+   #+end_src
+
+   A more complete and possibly more effective method, however, is in
+   the following example.  Like the preceding one, the Encrypted Note
+   object contains OpenPGP encrypted data in the =content= property.
+   A =summary= is optional and *may* indicate that the content is
+   encrypted if the Encrypted Note is being posted publicly (see next
+   section).
+
+   The encrypted data, however is an entire ActivityPub object
+   including source format which may be rendered by a recipient's
+   software and which *may* include a Signed Note as described above.
+
+   #+begin_src javascript
+     {
+	 "@context": ["https://www.w3.org/ns/activitystreams",
+		      { "@language": "en-AU" } ],
+	 "type": "Encrypted Note",
+	 "id": "http://snuffy.adversary.org/posted/encrypted-thing",
+	 "to": "http://snuffy.adversary.org/inbox",
+	 "cryptographic-protocol": "openpgp",
+	 "encrypted": {
+	     "content": "-----BEGIN PGP MESSAGE-----\n\n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\nO8rHVVfv5pA7bk3Fqy39QZz2OgR0PExy\n=DCuG\n-----END PGP MESSAGE-----\n",
+	     "mediaType": "application/pgp-encrypted+activitystreams",
+	     "signingKeyID": None,
+	     "recipientKeyIDs": [ "9CBEF6B7E0DF72CF91009AA5C98BAA1862E4484D" ],
+	     "cipher": "TWOFISH",
+	     "encryptionAlgorithm": "ELG",
+	     "timestamp": None
+	 }
+     }
+    #+end_src
+
+    This second method of encrypting ActivityPub or Activity Streams
+    data would enable providing signed information without revealing
+    publicly which key actually signed the that data except to the
+    intended recipient(s).
+
+
+*** Encrypted Public Messages
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-encryption-pubmsg
+    :END:
+
+    It would be possible to post an encrypted message publicly, but in
+    which the recipients' key IDs were hidden using any of the
+    =hidden-recipient= (=-R=), =hidden-encrypt-to= or =throw-keyids=
+    options available when using GPG.  For such messages the second of
+    the two options in the previous section is likely to be the most
+    useful, but it could be used with the first.
+
+    This would enable the use of a public stream of objects and
+    activities as a “dead drop” as a means of providing anonymous or
+    pseudonymous communication with any other party and without
+    requiring a means by which that party might be directly identified
+    by others.
+
+
+** Authentication
+   :PROPERTIES:
+   :CUSTOM_ID: crypto-auth
+   :END:
+
+   There are multiple methods by which OpenPGP keys could be employed
+   to provide authentication services between a client and server, In
+   particular as an alternative to using passwords or two-factor
+   authentication when used in conjunction with OAuth tokens for
+   sessions.
+
+   These methods have the additional advantage of providing a means by
+   which a remote server could confirm the identity of a user of
+   another server without requiring the transfer of any sensitive or
+   secure data between the two servers.  For the most part this
+   advantage stems from confirming a status is signed by the same key
+   as used on that remote server, but it could also be used to
+   directly authenticate in order to access any private messages of a
+   local user intended for that user and in the local user's
+   ActivityPub outbox.
+
+
+*** Authentication With Signing Keys
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-auth-sign
+    :END:
+
+    Utilising signing keys or subkeys would enable a means of
+    authentication with a server without requiring an ongoing session
+    between the client and the server.  This could be used to
+    facilitate a secure update or activity even across an insecure
+    connection without compromising the security of the account
+    itself as the server would be able to determine the authenticity
+    of the activity and any relevant objects by verifying the
+    signature alone.
+
+
+*** Authentication With Encryption Keys
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-auth-encrypt
+    :END:
+
+    Utilising encryption subkeys would enable a means of establishing
+    a secure session's token exchange which does not rely on the
+    transmission of a password, two-factor authentication or other API
+    key, as is most commonly utilised.  Instead the server simply
+    issues the token for that session in an encrypted format.  Since
+    only an authorised user or client with control of the OpenPGP key
+    could decrypt the data and obtain the token.
+
+
+*** Authentication With Authentication Keys
+    :PROPERTIES:
+    :CUSTOM_ID: crypto-auth-squared
+    :END:
+
+    OpenPGP authentication keys or subkeys are intended for use with
+    protocols like SSH or other remote access.  In spite of the name
+    they may be less useful in this use case.  Nevertheless, it would
+    be possible to configure a server to accept connections utilising
+    an authentication key or subkey to establish an authorised
+    connection from the client to the server.
+
+
+* Additional Technical Notes
+  :PROPERTIES:
+  :CUSTOM_ID: tech
+  :END:
+
+
+** Data size limitations
+   :PROPERTIES:
+   :CUSTOM_ID: tech-size
+   :END:
+
+   Since the conversion of encrypted binary data in the GnuPG format
+   to radix64 encoded ASCII text generally adds to the size of the
+   output data, determined according to both the size of the original
+   input data and the size of the keys to which that data is
+   encrypted, the maximum message size *should not* be arbitrarily
+   limited in the same way that many ActivityPub objects are limited.
+   The common limitation of five hundred characters per status to be
+   found with many Mastodon servers, for instance, would severly
+   hamper the ability to usefully employ any of these options.
+
+
+** Metadata and Forward Secrecy
+   :PROPERTIES:
+   :CUSTOM_ID: tech-metadata
+   :END:
+
+   The nature of ActivityPub and Activity Streams 2.0 data is such
+   that there is an inherent leakage of metadata with each object and
+   activity posted to a stream.  As a consequence there are certain
+   limitations on what can or should be concealed.  There are,
+   however, methods of mitigating that leakage.  A good example being
+   the second message encryption method described above.
+
+   Forward secrecy is a little more difficult with a messaging format
+   like this, even where it appears to be a stream to an end user.
+   This is due to each object being separate packages in that stream
+   rather than the data being transmitted as a single encrypted
+   session originating with the author and ending with the recipient
+   in real time.  Even in those circumstances in which the overall
+   communication (e.g. a conversation) does occur in real time or near
+   real time.
+
+   Nevertheless, between using OpenPGP keys with pseudonymous
+   identifiers linked to the ActivityPub stream end points and
+   minimising the amount of data revealed by encrypted content, there
+   are points which can facilitate this process.  In many respects
+   this could be done in a manner not too dissimilar to the use of
+   anonymous remailers and posts to the old [[nntp://alt.anonymous.messages][alt.anonymous.messages]]
+   USENET news group.
+
+
+* References
+  :PROPERTIES:
+  :CUSTOM_ID: refs
+  :END:
+
+  TBA.
+
+
+** Normative References
+   :PROPERTIES:
+   :CUSTOM_ID: refs-norm
+   :END:
+
+
+** Non-Normative References
+   :PROPERTIES:
+   :CUSTOM_ID: refs-non-norm
+   :END:
+
+
+** Informative References
+   :PROPERTIES:
+   :CUSTOM_ID: refs-inform
+   :END:
+
+
+* Copyright and Licensing
+  :PROPERTIES:
+  :CUSTOM_ID: copyright-and-license
+  :END:
+
+
+** Copyright (C) The GnuPG Project, 2018
+   :PROPERTIES:
+   :CUSTOM_ID: copyright
+   :END:
+
+   Copyright © Benjamin D. McGinnes, 2018.
+   Copyright © The GnuPG Project, 2018.
+
+
+** License GPL compatible
+   :PROPERTIES:
+   :CUSTOM_ID: license
+   :END:
+
+   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 armoured 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).
+
+[fn:2] Though the GnuPG Project is most well known for implementing
+the OpenPGP protocol, it does include support for S/MIME amongst the
+cryptographic engines (i.e. =gpgsm= or =gpgsm.exe= on Windows).
+
+[fn:3] Named after the Woolly Mammoth character in /Sesame Street/, of
+course, and who was originally believed to be Big Bird's imaginary
+friend.
+
+[fn:4] 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:5] The session key for the encrypted message in this example is:
+10:CAADC2A355B8DFA2798CCC42386544DDE490EBDFA12CFD663197EBAA61460879
+
+[fn:6] The session key for the second encrypted message example is:
+10:63A611B7B935B654100104F057BBF3B76D725AFCE45AFB83623A9C480DAED732

-----------------------------------------------------------------------


hooks/post-receive
-- 
The GnuPG website and other docs
http://git.gnupg.org




More information about the Gnupg-commits mailing list