DID Key Management Harmonization Proposal #1

This is an attempt at providing a harmonized DID Key Management
proposal. It contains aspects that will most likely be distasteful for
many in the group, but achieves all of the following requirements that
have surfaced during the DID Spec Hardening discussions:

R1. All data structures can be treated as plain 'ol JSON.
R2. All data structures can be extended via JSON-LD.
R3. All data structures are compatible with both a tree-based model AND
    a graph-based model (no philosophical nor technical conflicts).
R4. There is a simple algorithm for locating public keys owned by
    an entity represented by the DID.
R5. Authentication and encryption use cases are supported.
R6. Design allowances are made for authentication via biometrics, smart
    contract, and oracles.
R7. Ambient authority is protected against to a certain extent.
R8. Non-correlation use cases are supported.
R9. There is a very clear extensibility story both for JSON and JSON-LD.
R10. It is clear where non-owned public keys go.
R11. Multiple encoding types for public keys are supported with a clear
     extensibility story for other types of cryptographic primitives.

The suggested high-level DID Document data structure is this:

{
  "id": "did:example:123456789abcdefg",
  "publicKeys": [ ... list of public key objects ... ],
  "authentication": [ ... list of authentication suites ... ],
  "services": [ ... list of services ... ]
}

If we want to (eventually) support encryption, biometrics, smart
contracts, oracles, etc.... we could extend like so:

{
  // "cryptographic" building blocks
  "publicKeys": [ { ... }, ... ],
  "biometricTemplates": [ { ... }, ... ],
  "smartContracts": [ { ... }, ... ],
  "oracles": [ { ... }, ... ],

  // applications/purposes
  "authentication": [ { ... }, ... ],
  "encryption": [ { ... }, ... ], // unsure about this one

  // verifiable credentials
  "credentials": [ { ... }, ... ],

  // services
  "services": [ { ... }, ... ]
}

Now to define what each of these things do.

publicKeys
----------

This property lists any public key cryptographic material that is owned
by the entity represented by the DID (or a delegate). Biometric
material, smart contracts, etc. do not belong in this field and an error
should be thrown by processors if any non-owned non-public key data is
found in the publicKeys field.

This field MUST NOT be directly used for authentication purposes,
instead the `authentication` field SHOULD be used, which will reference
a key in this publicKeys array (if the authentication suite is a public
key based authentication suite).

An example of the contents of this field are here (but don't pay too
much attention to it as we can tweak what goes in the field later):

{
  ...
  "publicKeys": [{
    "id": "#key1",
    "type": "RsaSigningKey2017",
    "owner": "did:example:123456789abcdefg",
    "publicKeyPem": "-----BEGIN KEY...END KEY-----\r\n",
    "publicKeyJwk": {...}
  }],
  ...
}

Note that the cryptographic purpose of the key is included in the type
field, but there is no "purpose" field in the key by design. More on
this below in the section labelled "Authentication Algorithm".

authentication
--------------

This property lists all of the authentication suites (and references to
cryptographic material) that the entity represented by the DID deems
valid for the purposes of authentication. For example:

{
  ...
  "authentication": [{
    "type": "RsaKeyBasedAuthentication2017",
    "publicKey": "#key1"
  }],
  ...
}

Note that this DOES NOT mean that an application, such as a website
performing login authentication, must accept all authentication
mechanisms listed in the DID Document. The list of acceptable
authentication mechanisms will be the union of what the DID Document
specifies and what the application checking authentication accepts.

Authentication Algorithm
------------------------

Given the following DID Document:

{
  "id": "did:example:123456789abcdefg",
  "publicKeys": [{
    "id": "#key1",
    "type": "RsaSigningKey2017",
    "owner": "did:example:123456789abcdefg",
    "publicKeyPem": "-----BEGIN KEY...END KEY-----\r\n",
    "publicKeyJwk": {...}
  }],
  "authentication": [{
    "type": "RsaKeyBasedAuthentication2017",
    "publicKey": "#key1"
  }],
  ...
}

The authentication algorithm would be the following:

Assume an authentication server, an authentication client, and a DID
Document (ddoc).

1. The authentication server provides either a signature challenge to
   the authentication client, or there is a mechanism that is capable
   of automatically generating the signature challenge.
2. The authentication client uses a key listed in ddoc.authentication to
   digitally sign the challenge and deliver it to the authentication
   server.
3. The authentication server fetches the DID Document and looks in
   ddoc.authentication for key used in the signed challenge
   (challenge.signature.creator).
4. If the key object is a reference, the authentication server looks in
   ddoc.publicKeys for the key.
5. If the key is found, and it meets the requirements specified for
   the authentication suite (e.g. key size >= 2KB, secp256k1, etc.),
   the public key information is used to check the signature on the
   challenge.

There are certainly variations to the algorithm that we can discuss, but
that would be the general structure of it, which would be fairly simple
to implement in code, operating using a stock JSON processor.

Meeting the Requirements
------------------------

> R1. All data structures can be treated as plain 'ol JSON.

This requirement is met because we have not used any features of JSON-LD
or graph-based data models.

> R2. All data structures can be extended via JSON-LD.

This requirement is met by adding a JSON-LD Context to the DID Document
that defines extensions.

> R3. All data structures are compatible with both a tree-based model
> AND a graph-based model (no philosophical nor technical conflicts).

This requirement is met because we force the document to have a
well-known tree-based model with an algorithm that assumes a tree-based
layout. JSON-LD processors could force the layout using JSON-LD Framing.

> R4. There is a simple algorithm for locating public keys owned by an
> entity represented by the DID.

This requirement is met by just looking in the `publicKeys` property.

> R5. Authentication and encryption use cases are supported.

The authentication requirement is met as demonstrated above. The
encryption use case is a simple variation on the authentication use case.

> R6. Design allowances are made for authentication via biometrics,
> smart contract, and oracles.

This requirement is met by defining new authentication suites and
specific containers for other types of cryptographic material as
outlined above.

> R7. Ambient authority is protected against to a certain extent.

This requirement is met by specifically NOT including an
application/purpose in the key material and instead forcing that
information to be fetched through other means (e.g. the authentication
property).

There is still a danger that one completely mis-implements the
specification and just searches through publicKeys. A mitigation for
this would be to remove the publicKeys property, which a few seem like
they would be unlikely to do.

> R8. Non-correlation use cases are supported.

This requirement is met by ensuring that the DID Method doesn't support
any mechanism that would lead to correlation (such as certain types of
public keys or biometrics, etc.).

> R9. There is a very clear extensibility story both for JSON and
> JSON-LD.

This requirement is met by pure JSON implementations either extending
via JSON-LD and then hard-coding to the JSON-LD properties OR by
prepending all DID Method specific extensions with the DID Scheme:

e.g. uportSmartContractFoo or sovAccumulatorBar

Although, I strongly advise against the latter as the former is just as
easy to do.

> R10. It is clear where non-owned public keys go.

This requirement is met by allowing non-owned public keys to go anywhere
in the document they are needed, but specifically NOT in the publicKeys
array, which are reserved for public keys managed by the entity
represented by the DID (or a delegate).

> R11. Multiple encoding types for public keys are supported with a
> clear extensibility story for other types of cryptographic
> primitives.

This requirement is met via the publicKeyPem and publicKeyJwk design
pattern where the encoding is a part of the property name. Other types
of cryptographic primitives are supported by creating new, specific bags
for that information.

I'll stop there to see if we have buy in for this approach. There are
some corner cases and security implications that still need to be
discussed, but those discussions are easier to have once we can settle
on what the top-level branches of the document could look like.

What did I miss? Does the approach above create any new problems? Are
there remaining concerns that would not allow us to proceed down this path?

-- manu

-- 
Manu Sporny (skype: msporny, twitter: manusporny, G+: +Manu Sporny)
Founder/CEO - Digital Bazaar, Inc.
blog: The State of W3C Web Payments in 2017
http://manu.sporny.org/2017/w3c-web-payments/

Received on Friday, 5 January 2018 21:51:00 UTC