- From: Manu Sporny <msporny@digitalbazaar.com>
- Date: Fri, 5 Jan 2018 16:50:32 -0500
- To: W3C Credentials CG <public-credentials@w3.org>
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