hyperledger / aries-rfcs

Hyperledger Aries is infrastructure for blockchain-rooted, peer-to-peer interactions
https://hyperledger.github.io/aries-rfcs/
Apache License 2.0
324 stars 218 forks source link

RFC 0056 & RFC 0023 Usage of inline public keys #201

Open tplooker opened 5 years ago

tplooker commented 5 years ago

A reoccurring issue has been how to sufficiently represent inline keys in a concise syntax whilst preserving the required information around a public keys encoding and underlying type.

The did:key method appears to solve these issues by leveraging the following list of multicodecs.

Using this method we could replace any current references we currently have to inline public keys that at present do not include any information about the public keys encoding or type.

An example of this in the service decorator instance would be the following.

{
    "@type": "somemessagetype",
    "~service": {
        "recipientKeys": ["B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u"],
        "routingKeys": ["B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u"]
        "serviceEndpoint": "https://example.com/endpoint"
    }
}

Would change to

{
    "@type": "somemessagetype",
    "~service": {
        "recipientKeys": ["did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"],
        "routingKeys": ["did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"]
        "serviceEndpoint": "https://example.com/endpoint"
    }
}

Whereby resolvingdid:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH would yield the following

{
  "@context": "https://w3id.org/did/v1",
  "id": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
  "publicKey": [
    {
      "id": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
      "type": "Ed25519VerificationKey2018",
      "controller": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
      "publicKeyBase58": "B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u"
    }
  ]
 //Further information from the did doc omitted
}

Hence yeilding the underlying public key of B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u, its encoding of base58 in this case and the type of key it is Ed25519VerificationKey2018

tplooker commented 5 years ago

@dhh1128 @kdenhartog @TelegramSam

dhh1128 commented 5 years ago

For the time being, I am STRONGLY opposed to introducing a dependency on did:key. I don't agree with any of the extra semantics that this method wants to introduce -- specifically the ones related to assertionMethod, capabilityDelegation, capabilityInvocation, and keyAgreement. This is because, while I love the OCAP model, the DB method is linked to an implementation of OCAP (OCAP-LD) which I consider dangerous and unnecessary; Sovrin-style credentials are a safer, cheaper, and more privacy-respecting OCAP solution because of the way they test the delegation chain and revocation properties. Now, I am not trying to argue the OCAP issue in this ticket, and it's entirely possible that we could converge over time--but I don't want to jump on the bandwagon of this DID method and accept a bunch of assumptions that we later have to unwind.

However, I think the key encoding mechanism is clever and useful. So why don't we do what you are proposing, except not use the did:key: prefix. That is, just provide the keys in encoded form, such that if we decide to use did:key later, we can--and if we don't, we haven't lost anything because we still have the property we truly need.

swcurran commented 5 years ago

I agree with Daniel. The encoding is very useful, but the highly opinionated derived DIDDoc is asking for trouble. If there was a way to define our own DIDDoc template, that would be helpful, but that not be did:key. I think that without explaining to developers the purpose of all the fields in the generated DIDDoc (using phrases other than "ignore this"), we're asking for trouble.

I do like the concise encoding.

tplooker commented 5 years ago

@dhh1128 point taken, perhaps more education and understanding of some of the implications that this method entails is required. Are you prepared to document some of your concerns so we can evaluate, alternatively I'm happy to jump on a call to discuss further, or perhaps we can put this on the agenda for the WG call? To me inventing a new syntax that has no prefix feels like wasting/duplicating alot of the work of the DID spec which is to establish a uniform data model behind these style of identifiers.

tplooker commented 5 years ago

Tagging #104 explicitly because of its overlap I didn't see until I opened this issue

dhh1128 commented 5 years ago

inventing a new syntax that has no prefix feels like wasting/duplicating alot of the work of the DID spec

Actually, there is a prefix on the key value in my proposal--the one given by multicodec. I'm proposing that we use it exactly the way it was designed--as a prefix for keys. What I'm proposing to jettison is the did:key prefix, which is NOT "work of the DID spec" but of a specific DID method that is brand new to the public eye. Using did:key as a prefix for keys (as opposed to DIDs) is a nonstandard way to encode keys that would ignore the the DID spec -- not the other way around.

Re. concerns:

First concern: the items we're listing in ~service.recipientKeys and ~service.routingKeys are keys, not DIDs. Putting DIDs where keys belong is an error. (Yes, I know that in did:key, a key's id and the DID's id are identical by design. I think that's a conceptual problem, because it gives two nodes in the same JSON that have the same id value; go look at the sample DID docs. Now you need specialized parsing logic to disambiguate. Even if that's more of an annoyance than a problem, we can't hard-code into DIDComm an odd assumption about DID~key equivalence that happens to only be true of one DID method.)

Second concern: The OCAP solution that DB is advocating is, if I understand correctly from conversations with Manu, an evolution of ZCAP-LD. Manu told me in our last conversation a few weeks ago that the current spec is stale. However, it seems clear from reading it that an object capability is going to be validated by traversing a chain. If I have a capability that's delegated and/or attenuated from A to E (A -> B -> C -> D -> E), then I have to walk the chain back to A to confirm the OCAP is still valid. This means every party in the delegation chain finds out when downstream usage occurs, which is a privacy problem--not to mention a fragility problem as it requires all parties in the chain to be available (or to have a queryable automated system available) whenever a delegation chain is validated.

Third concern: I'm concerned that using ZCAP-LD as did:key imagines externalizes a new dependency that's quite complex, at exactly the place where what we need is utter simplicity (raw keys). To know if someone is using their DID correctly, you now need a whole new document format (to represent your OCAP), a whole new validation mechanism (to parse the doc, traverse the chain, and consult with all holders of the doc about revocation), etc. The architectural dependency lines should go from simpler to more complex, with DIDs being near the bottom; now we're putting something beneath DIDs that's complex again--and we're doing it for the very simple set of use cases that you've advocated, where we don't want the complexity of establishing a connection yet. That's the wrong place to add complexity. (We could get around this by saying that none of the DIDs used in these ~service decorators are allowed to have fancy delegation, but this would be inventing a subset of did:key that's not in that spec.)

I have more concerns, too. We can certainly discuss on a community call.

SmithSamuelM commented 5 years ago

I proposed this elsewhere but the main issue with bare public keys is that there is no explicit indication of the crypto suite type so a user does not know how to verify signatures. Merely including the crypto suite type as a DID URL query string is a simple way to provide this. Another approach would be to use a did matrix parameter. The latter can be universal but complicates the DID resolver the former would be on an application by application basis but does not encumber the resolver its merely a convention that in this case would be respected by DID Comm. This avoids creating a new DID method that is OCAP based.

SmithSamuelM commented 5 years ago

A related discussion in the last couple of W3C DID meetings is where to put additional behavior for more types of verification. What tends to be happening is that proposers want to add functionality to the DID resolvers which is a death spiral by design, that is, as DID resolvers become more complex they get slower and more prone to failure and exploit this makes resolution increasingly expensive in general even for applications which do not need the additional behavior which induces more caching and other workarounds to avoid resolution etc etc. The suggested solution is to keep resolvers simple and provide additional verification through service endpoints that are specific to the additional behaviors. The root of trust for a DDo is the authentication block in the DDo. Changes to the DDo are governed by the DID CRUD methods. Thus any service endpoints are authN authZ by the crud methods and the Auth block. This means that there is little need to add anything to the DDo that the DID resolvers needs to do besides Auth and CRUD. One can other make their DID methods more complex or add service endpoints with more complexity. Either work and are less problematic than adding additional behavior to the resolver. The latter means that fewer special purpose methods are needed just special purpose endpoints. This is a more scalable solution IMHO

SmithSamuelM commented 5 years ago

DID resolution should be a lightweight indirection to some DID service endpoints where all the work is performed. As opposed to a heavy weight one stop shop.

SmithSamuelM commented 5 years ago

Adding the auth block to a DID URL vis query parameters allows for ephemeral DIDs to avoid resolution entirely. Which is even more lightweight.

dhh1128 commented 5 years ago

@SmithSamuelM: Let me propose a requirement that may make it obvious why I'm not going down the DID URL route.

It should be possible to use, in the ~service key lists, keys that are not associated with any DID, anywhere, ever. For example, it should be possible to use a key that's part of my SSH config, but not involved in DID-land at all.

To be fair, this requirement has never been stated anywhere before, but neither has the opposite (that all keys will always be DID keys). And given the fact that we're talking about using this in places where we either do not yet have, or do not ever intend to have, a DID-based relationship, I think it's a reasonable one.

Given that requirement, can you see why I'm not going down the DID URL query string route? Multicodec does specify the crypto suite for the key, so we don't have the raw key interpretation problem you highlighted.

SmithSamuelM commented 5 years ago

One weakness of the existing internet is DNS resolution. It’s slow buggy and insecure. We don’t want IMHO to repeat those mistakes.

SmithSamuelM commented 5 years ago

Given multicodec provides the crypto suite than the query string is not needed. But being a did still allows some degree of future proofing. I guess my inclination is to make DID work well in these applications not add another identifier class. The core feature of a DID is that its a self-certifying identifier. A public key is not quit a self-certifying because it is not resolvable but requires additional context whereas a DID is resolvable. This is a powerful feature. One can always add context to make a public key have meaning, but the whole basis of what many call Identity Based Crypto is to leverage the idea that the crypto context is self-contained in the identifier. So I always ask myself the question is this a use case where there is crypto that could be identity based crypto but isn’t and if not my presumption is that it should be unless there is a really good reason why not and context provided elsewhere is actually a reason to change. One of the roots of security problems and complexity is providing the context of the crypto elsewhere. One place is better than two places.

SmithSamuelM commented 5 years ago

It’s a philosophical orientation.

SmithSamuelM commented 5 years ago

But it may be that I am way off base here if its legacy standards we are trying to support.

SmithSamuelM commented 5 years ago

The way to get both speed and future proofing is to use caching. This can be done with identity based crypto by making identifier itself be the catche and then have the resolution happen when the cache expires. Thus an ephemeral DID could have the crypto suite and cache expiration be embedded in the query string so that that resolution only happens if the DID is still valid after the cache expiration. (Other semantics would have the DID only be valid for the cache and then resolution never occurs (truly ephemeral).

Anyway just providing some food for thought.

SmithSamuelM commented 5 years ago

A ordered dict (key: value pairs, or an ordered tuple of pairs, or a URL with query are all functionally equivalent representations and can be used interchangeable as identifiers for identity based crypto. So making them all DIDs is merely adding resolvability for future proofing and indirection. In general those two features are very powerful and may come at little cost if employed wisely. So everywhere I see identifiers with key material expressed as any one of the three I recognize them as functionally equivalent so I ask the question could it be a DID otherwise.

SmithSamuelM commented 5 years ago

Ordering makes the dict and tuple consistently6 hashable so they can be identifiers in their own right not merely encodable as a URL.

SmithSamuelM commented 5 years ago

The semantics of control embedded in a ‘DID is the essential feature of self-certifiability so having only one semantic for self-certifiability makes composing more complex behaviors decomposable to fewer primitives. This is an essential complexity reduction technique.

tplooker commented 5 years ago

Thanks, I do understand that the multi-codec identifier becomes the prefix, however I'm still not convinced with this approach. I understand that did:key is still forming and hence is not a complete solution but I am wondering if this is at least an opportunity to collaborate on forming a generalized ephemeral did solution.

The core of my argument is what do we want to refer to other parties in the ecosystem as, keys or some more generalized type of identifier? Because supporting both seems like a strange fork. The solution in my mind is simple whenever you are talking about a key that belongs to a did doc, reference it via a did-url, because chances are if you are authenticating a message from or sending a message to, you will be speaking about them in the context of their did not key. If it is an ephemeral key you are authenticating a message from or sending a message to, why not construct an ephemeral did so that the way in which you identify subjects is uniform. Otherwise in parsing fields like recipientKeys or routingKeys you will have to always have a branch of logic that is looking for the did prefix passing it to a did resolver and another branch of logic that tests if its multi-codec public key and instead perform some piece wise logic that is non-standard and will return some implementation specific understanding of the public key. This duplication creates headaches wherever this functionality is required and I see little benefit to effectively creating another identifier to a public key.

Another important observation to note is although DID's were not designed to be entirely human memorable, they are in most cases human identifiable, which is an important distinction to make. Because if we invest in creating a multi-codec form with no human identifiable prefix like did:key this will potentially be the source of much confusion, i.e how do I as a human disambiguate between my base64 public key that was spat out of some system versus my multi-codec public key, see an extract taken from the example refereed to above.

B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u => z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH

Or with did:key prefix it becomes far less ambiguous.

B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u => did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH

In regards to your second and third concerns raise in your points above, my understanding of the applications of OCAP's is different to what you describe, in particular how you describe validating attenuated delegation in an OCAP model. For instance, the delegation chain can be embedded into an OCAP rather than having to traverse a chain and the revocation check can be either be a call back to the original issuer or it could reference some global revocation infrastructure like what Sovrin provides. The point i'm trying to make is that is an implementation specific detail and I don't think did:key (but I may well be wrong) has a hard opinion on the exact implementation and even in the event it does, is there still an opportunity to discuss this as an issue with one possible usage of did:key rather than something fundamental to did:key?

SmithSamuelM commented 5 years ago

@daniel. I am not supporting did:key I would rather have a true ephemeral DID. @tplooker proposed did:key. But my comments are that this is similar to ephemeral DID and I think we should have an ephemeral did not did:key

tplooker commented 5 years ago

@dhh1128 to your point about SSH above, unless you are talking about putting raw public keys in the fields described which re-introduces the ambiguity we are trying to solve, you will still have to cast them to some other representation before using i.e a multi-codec base or something like did:key

tplooker commented 5 years ago

@SmithSamuelM I am happy to explore a more pure ephemeral did too if we deem did:key is too opinionated about its usage, what I am opposed to is creating a new identifier class i.e just using the multi-codec prefix to a public key.

SmithSamuelM commented 5 years ago

@tplooker. Yes I share the same concern. I resist creating new classes of identifiers when I think that a DID will do. DIDs are sufficiently flexible that we should spend some effort adapting them vs just creating non-DID identifiers that are almost DIDs.

SmithSamuelM commented 5 years ago

The URI speci proved to be a very resilient and long lived specification because it had a Goldilocks amount of flexibility. I would like DIDs to follow suite.

SmithSamuelM commented 5 years ago

Fundamentally I am more in agreement with @dhh1128 than not. As long as the multicodec includes the crypto suite it is a self contained identifier than can be used in general for encrypting did:comm. There is no need for it to be a DID. The question for me is could an ephemeral DID provide the same functionality but with additional features. The key differentiator would be that a truly ephemeral DID does not require resolution to a DID resolver. If it did then we add a performance issue. I don’t think its a layering or recursion problem unless did resolution READ is DID:COMM encrypted. I was not aware that that was a thing. But should that be true then an ephemeral only DID is required which is functially the same. The only advantage then being the commonality of syntax with a DID allows code reuse of tooling for parsing etc. So its not a strong difference.

SmithSamuelM commented 5 years ago

In general there are multiple use cases where we use crypto as part of a bootstrap of capability. A true Ly ephemeral DID would define a common syntax and semantics for all these bootstrap functions. In that sense a truly ephemeral DID is a different kind of DID. We could call it something else but then it would be good to define a new identifier class that is still identity based crypto (aka self-certifying identifiers) but are completely self-contained and ephemeral. I like the idea of calling these ephemeral DIDs rather than defining a new name and class but I understand they are un DID like in important ways.

SmithSamuelM commented 5 years ago

Attenuated Authorizations are a type of. Data not an identifier. They have an identifier but they are not the same as an identifier.

tplooker commented 5 years ago

@SmithSamuelM correct in my mind with an ephemeral DID you would use a DID resolver that would just inflate the DID into a minimal DID Doc quoting one key, so no actually resolution in the traditional sense is required. Conceptually ephemeral DIDs are similar to did:peer in the fact they do not rely on a ledger, but they go one step further and remove the dependency on local state and maintaining local state. It is important to note I'm not raising this comparison to justify ephemeral DID's as a replacement to peer DID's, I think there are very valid use-cases for both, I'm merely pointing out that we already have an example of a did not anchored to a ledger.

tplooker commented 5 years ago

Also creating another identifier standard is not a small undertaking, so we should approach this from the angle of why ephemeral did's do or do not fit under the did spec before we decide to create a new type of identifier, rather than the other way around.

SmithSamuelM commented 5 years ago

The core feature of a self certifying identifier is that the public key of a public private signing key pair is included in the identifier (or at least a fingerprint). These means that any attestations signed with the private key may be verified with the public key in the identifier. If all one needs is a public private key pair to control the attributes associated with an identifier then the identifier provides the public key. The assumption is that the crypto suite used for the associated signature is known. If the crypto suite is also provided in the identifier via query parameters for example then that assumption goes away and the tooling is now future proofed. Control over the attributes is proven via signatures and the identifier provides alll the information a verifier needs to verify. Notice that in this case no resolution aka no DDo is needed for this simple case. The primary purpose of a DDo is to support a persistent did that must survive for multiple uses. One of the things that happens is keys are exploited due to exposure so the did doc provides a way to rotate the private key but still keep the same public key embedded in the identifier. In other words the DDo enables key management for the long term viability of a persistent did. A secondary purpose of a did document is indirection to services affiliated with a given did. An ephemeral did does not have long term key management or affiliated services so has no need for a did document. It’s a one time use key pair or short time use. However tooling for DIDs may involve resolution so an ephemeral did is resolvable but trivially so.

The purpose of the did method is to provide authenticated CRUD operations for updating the two purposes 1) key management. 2) indirection to affiliated services. Anything more than this will overly complicating did resolvers. Any new features besides key management may be provided with the indirected services. Because an ephemeral did is not persistent the did document may never need update for rotating keys but merely crypto suite updates.

For encryption keys a derivation algorithm may be used from the private key and a path in the query string. This also may be used to bootstrap a Diffie Hellman exchange. Nowhere is did resolution required because the did itself is self contained as long as the crypto suite is known. Additional properties like detecting stale ephemeral DIDs might be useful. In this case did resolution may or may not have a use.

Did resolution is all about key management and indirection but most important is key management.

Sent from my iPad

On Aug 27, 2019, at 04:33, Tobias Looker notifications@github.com wrote:

@SmithSamuelM correct in my mind with an ephemeral DID you would use a DID resolver that would just inflate the DID into a minimal DID Doc quoting one key, so no actually resolution required. Conceptually ephemeral DIDs are similar to did:peer in the fact they do not rely on a ledger, but they go one step further and remove the dependency on local state and maintaining local state. It is important to note I'm not raising this comparison to justify ephemeral DID's as a replacement to peer DID's, I think there are very valid use-cases for both, I'm merely pointing out that we already have an example of a did not anchored to a ledger.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

dhh1128 commented 5 years ago

I left an extended comment in #104. See https://github.com/hyperledger/aries-rfcs/issues/104#issuecomment-525396519.

dhh1128 commented 5 years ago

By the way, everything I said over in #104 applies here. What we are listing in the recipientKeys and routingKeys arrays are really, truly keys. They are not identifiers for agents. The fact that agents might map to these keys is incidental and not guaranteed. We only need these values as numeric input to cryptographic functions--nothing more.

tplooker commented 5 years ago

@dhh1128 to be clear are you saying the recipientKeys and routingKeys fields should only ever be populated with this new type of concise identifier, which is a multi-codec public key?

dhh1128 commented 5 years ago

I think so.

However, let me think out loud a little bit. In the other ticket (#104), I talked about the relationship between crypto algorithms and DID resolution, and I made the claim that the envelope should be verifiable/decryptable with nothing but a key value; it should never depend on even a degenerate form of DID resolution.

The scenario explored in this issue has a lot in common, but there are some differences. The most important one is that the values in the recipientKeys and routingKeys arrays are given to two different algorithms. One is cryptographic (pack() for these keys). But the other is network-related (the algorithm that actually delivers bytes to a remote party). While I still maintain that it is a mistake to make crypto depend on DIDs, I don't feel the same way about network delivery. You already have high-level DID-aware code in play if you are looking at a ~service decorator or a DID doc, so maybe we could be less pure about how things are encoded in recipientKeys and routingKeys. Here, we are making a tradeoff that is a bit less crisp:

On balance, I think I'd prefer to err on the side of explicitness (key values, not key references). If I put the ~service decorator on two successive messages to Alice, and the lists contain key values instead of references, and my key values have changed, I will be guaranteed that Alice notices. Whereas if I put the ~service decorator on two successive messages and rotate my keys, but the key reference is stable, I have no idea whether Alice will notice.

So that's me thinking out loud. I could maybe be talked into a different answer. What I feel strongly, that I'm still pushing for is:

Where I could be convinced, maybe, is that key references are appropriate -- in which case the proper form of them would be the DID URL form that @SmithSamuelM has been advocating.

peacekeeper commented 5 years ago

I'm a bit late to a long discussion, but I like the following points made by @dhh1128:

the items we're listing in ~service.recipientKeys and ~service.routingKeys are keys, not DIDs. Putting DIDs where keys belong is an error

what we are listing in the recipientKeys and routingKeys arrays are really, truly keys. They are not identifiers for agents.

The other issue https://github.com/hyperledger/aries-rfcs/issues/104 has good thoughts on whether keys should be passed as inline values or as references, but in this issue here the original question seems to be whether inline keys should be passed as bare multicodec'ed values or as did:key. I think this decision should depend on whether something is being identified or not - as @dhh1128 put it in 4) We're not identifying.

Whenever a DID is used somewhere, let's ask the question "What's the DID subject?". If there's no good answer to that question, then probably just a (multicodec'ed) key value should be used instead of a did:key.

I suspect the answer to that question is linked to the discussion in the other thread on how much separation or integration there should be between the crypto layer and the DID layer.

peacekeeper commented 5 years ago

@SmithSamuelM

Because an ephemeral did is not persistent

This is just a minor detail, but I would argue a DID that doesn't support the Update or Deactivate operations is still "persistent", i.e. it will never be re-assigned to identify a different subject.

I think we should have an ephemeral did not did:key

I'm not sure I understand why you would not consider did:key to be "ephemeral" or what exactly you mean by that?

SmithSamuelM commented 5 years ago

@peacekeeper

Good question. What I mean by persistent is that the key management allows the DID to persist despite exposure of the associated keys. Keys become obsolete due to exposure and need to be rotated. A one time use key does not need to be rotated so the identifier is ephemeral in that sense. Clearly a DID which includes a UUID via the associated public key is a persistent string but the key management policy (ie one time use) may mean that the private key may not be persistently trusted. That is the identifier trust basis is not persistent and has an expiration even though the identifier itself is a UUID.

Also on subject. I am using DIDs in a general sense as unified identifiers which means the "subject" could be any item of data. What I mean by "UNIFIED" identifier can be found in these references

https://github.com/SmithSamuelM/Papers/blob/master/presentations/DID_Everything_OpenWest2019.pdf and https://github.com/WebOfTrustInfo/rwot7-toronto/blob/master/final-documents/A_DID_for_everything.pdf

swcurran commented 4 years ago

Discussed on the Aries Working Group call 2019.11.27. We tried to see if we could close this issue with a recommendation, but that didn't happen. Relevant points:

We hope to talk about this at the Connectathon next week and move this to the point that we can both take action on this and close this issue.

llorllale commented 4 years ago

@swcurran @kdenhartog

  • Counter to my earlier comment that many of the entries in the DIDDoc would not be useful in DIDComm, Tobias pointed out that likely most would be useful, including "keyAgreement" where a Curve25519 ECDH key is derived from an ed25519 public key.

I would like to know more about why some existing implementations are deriving the encryption key from a signing key. As far as I am aware, DID docs can include keys for "digital signatures, encryption and other cryptographic operations", so I don't see the reason for this conversion.

tplooker commented 4 years ago

@llorllale, I'm not sure I fully understand you question? Are you asking why are we using a single key for both encryption and signing?

llorllale commented 4 years ago

@tplooker not quite; I'm asking why some implementations derive the encryption key from the signing key (the RFC says the input is a signing key), instead of starting with an encryption key as input in the first place.

swcurran commented 4 years ago

@llorllale - that specific implementation's derive keys (or not) is a separate issue from this discussion. A discussion about that practice with the implementers would be needed. Perhaps that is a discussion needed around the did:peer DIDDocs that we expect - I'm not sure.

In the case being discussed here, we have (by definition) just one public key (a string) + the algorithm type. The transformation that is done with did:key is to take those two values and generate a standard DIDDoc with (mostly) string replacement, but in the case of the "keyAgreement", the derivation of a new public key from the initial one.

SmithSamuelM commented 4 years ago

One very good reason to start with a signing public/private key pair and then derive an encryption public/private key pair from the signing key pair is that now only one private key must be stored / remembered recovered. This reduces the key management load on the user and associated risk. The key management load on the user IMHO is the gating complexity for broad adoption of decentralized identifiers. Combining this approach of deriving encryption keys from signing keys with an HDKey algorithm where any number of signing key pairs may be re-derived from a single private key plus a public path per key then one starts to get scalable key management. So the HD keychain for signing becomes for free also an HD Key chain for encryption.

baha-ai commented 4 years ago

I disagree with deriving/converting encryption keys from signature keys as this poses a security threat. If a key is compromised, the hacker can derive/convert other keys and do more harm with only 1 key. This is more true for Ed25519 to X25519 conversions as they're 1 to 1 conversions. If a hacker lays their hands on the signature key, they can decrypt all DIDComm messages. To avoid this, signature keys should not be linked to encryption keys in any way.

llorllale commented 4 years ago

Note: this has implications for the out-of-band, did-exchange and connections protocols as they exist today, where the response is signed with a recipientKey sent in the invitation

swcurran commented 4 years ago

So discussion for tomorrow at the Aries WG call? @Baha-sk @llorllale -- can you lead the discussion? Your two notes cover it nicely - whether or not it is a safe practice, and if not, how it would affect what we are doing in various protocols.

Please confirm if you can make it -- I'm prepping the agenda now.

SmithSamuelM commented 4 years ago

@Baha-sk "I disagree with deriving/converting encryption keys from signature keys ". I agree with you in the general case. The one case, however, where this is acceptable in my view is to bootstrap ephemeral communications which is the peer did case. The exploit you talk about "lay their hands on the signature key" is just as valid an exploit for encryption keys as it is for signature keys. If your key management system is sufficiently weak that someone can "lay their hands" on your signature keys, what stops them from also laying their hands on your encryption keys as well? If on the other hand you adequately protect your signature keys, then deriving an encryption key from a signature key is only a little less hard to brute force exploit (as it its very very hard). The root of the problem is how do you manage your secrets. If your management of signature keys is so bad that you must protect your encryption keys using some other mechanism then your most serious problem is not that you are converting signing keys to encryption keys but how you are protecting your signing keys in the first place. There are some who erroneously hold that protecting confidentiality is more important than protecting authentication. I would argue that confidential but unauthenticated communication is much less useful than authenticated communication (confidential or not). There are some edge cases where you want confidential but unauthenticated communication but for real transactions it must be authenticated first and always. So protecting your signing keys is a first priority. Obfuscation of encryption keys is not protection. So protect your secrets well. Derived private keys from well protected secrets is the most practical approach to scalable key management. Not having derivable keys or a key management infrastructure based on derived keys will not scale and makes decentralized identity impractical.

SmithSamuelM commented 4 years ago

If you are going to encrypt lots of data (not merely bootstrap communications). Then you wouldn't want to use only one encryption key (derived from a signing key or not) you would want to use rotated encryption keys at least one per session and maybe one per so many MB of data. this gives you forward secrecy. So even if the first encryption key is derived from a signing key (for the bootstrap). The subsequent rotated (or ratcheted) encryption keys are not exposed should the original signing key be compromised. Simplistic rules of thumb about key management are usually wrong. Real world means you must rotate keys and build in support for key rotation. So if DID Comm is only bootstrapping a short set of messages one time with a set of keys, its not a problem. If you are using the same did comm keys indefinitely then that will eventually be a problem.

SmithSamuelM commented 4 years ago

In the general case for a key management approach based on derived keys, one starts with a root secret of sufficient entropy. This root must be extremely well protected. Then keys are derived from this root using a derivation process that preserves the cryptographic strength of the root. The derivation process should preserve the degree of cryptographic strength as a design parameter for your infra-structure (128 bits) is considered sufficient pre-quantum. Brute force exploit of 128 bits of cryptographic strength is a practical impossibility (pre-quantum). These first order derived keys may be roots in and of themselves but inhabit different infrastructure from the master root. This is a multi-valent key management infrastructure. Then other keys within the same infrastructure may be derived from these 1st order roots. These are the keys that actually get used or exposed. With self-certifying identifiers the public keys become part of the identifier are are used to derive the identifier. All the derived identifiers may be either ephemeral (one time short time use) or persistent. Persistent identifiers must be rotatable (ie their keys must be rotatable). Given this approach, all exploits become key management exploits that are recoverable up to but not including a successful compromise of the master root secret. When using multi-sig across entity boundaries then there may be multiple master secrets. So the critical analysis for any did com identifier is to answer the question. Is its use ephemeral or persistent? If ephemeral make sure it really is ephemeral (one time short time). If persistent then it must be rotatable.