decentralized-identity / keri

Key Event Receipt Infrastructure - the spec and implementation of the KERI protocol
Apache License 2.0
73 stars 21 forks source link

Simplify Delegated Events using Hetero Attachments #146

Open SmithSamuelM opened 3 years ago

SmithSamuelM commented 3 years ago

Background

When the delegated inception and delegated rotation events were first designed and implemented we did not have support for complex grouped hetero attachment types. Now that we do we are able to simplify some of the events. Recently working on event types for Transaction Event Logs (TELs) allowed us to do that design but informed with the capability of hetero attachments. This allowed us to simplify their design. TEL events share some similarities in terms of their security posture to delegated identifier events. They are both authorized in a KEL (Issuer or Delegator respectively) so share some of the same security considerations. This thinking about TELs prompted an understanding of a way to simplify delegated events in KERI.

Performance Problems Due to Synchrony Constraints of Existing Delegation Operation

Recall, that the protocol for creating delegated inception and rotation involves an exchange with two handshakes between the Delegator and Delegate. During this exchange the Delegator may not create any new events in its KEL. The Delegator is blocked until the exchange completes and this may include network timeouts due to delayed packets or dropped packets or connections. This creates a synchrony constraint which may cause performance issues at scale for Delegators. This was always recognized as a potential performance issue, but at the time there did not seem to be an alternative. With hetero attachments we now have an alternative that eliminates any synchrony in the exchange. The Delegator may create events asynchronously. The delegate must still block but the new proposed exchange has only one handshake not two..

For example suppose we have a delegated identifier node thats wants to do a rotation. It has to submit to the delegator node a request for a rotation. The delegator then responds with the event sn, type, and prior event digest of a new event it will creat to with an event seal to anchor the delegation. The delegator now has to wait for the delegate to respond with the finished delegated event so the delegator can digest it and then put an anchor seal to the finished delegated event in its new event. Once that is done the Delegate must get confirmation of the creation of the anchoring event in the Delegator's KEL before it is safe to publish the delegated event in its KEL. If any of these steps timeout due to network problems then it becomes a performance issue for the delegator. The delegator has to block its processing, waiting for a subsequent response from the delegate before it can finish creating the delegating event or any subsequent events.

The reason for the exchange is that the delegated events include in the signed portion of the event a location seal that includes the tuple `i, s, t, p' which are the compact labels for respectively, the delegators identifier prefix, the sequence number of the delegating event, the event type, and the digest of the prior event to the delegating event.

Security Considerations

However after some thought, however, only the the identifier prefix, i needs to be in the body of the delegated event. This makes a cryptographic commitment by the delegate to the delegator's key via the identifier. The other fields s, t, p enable a verifier to look up the delegating event and find the anchoring seal. They may be provided in an attachment for this lookup to occur.

From a security posture, KERI is not doing an atomic swap when it creates a delegation. A delegation is merely authorizing the delegated event. Multiple authorizations but from the same source (Delegator) provide equivalent authority, any one will do and more than one doesn't change that authority. For security the delegate needs to uniquely commit to the delegator as the source and the delegator needs to commit to the delegated event. If the Delegate did not commit to a Delegator then the same delegated event could be authorized by multiple Delegators which is an attack. But once the Delegate commits to a given Delegator then only one KEL will be authoritative for delegating seals (delegations). Which specific event creates the delegation (delegating seal) or more than one does not matter they are all similarly verifiable as authorized. All that a verifier needs is a reference to find one of the delegating seals, which one doesn't matter.

To elaborate, I see no advantage to an attacher to having multiple authorizing seals to the same delegated event. The authoritative ordering of authorized events is determined by the order they appear in the delegate's KEL not the order that the authorizing seals appear in the delegator's KEL. The first seen policy of any verifier of both the delegate's KEL and the delegator's KEL are what are decisive for fully verifying a delegate's KEL. But the only ordering that is verified when verifying a delegate's events is the ordering of events in the Delegate's KEL as determined by that KEL. The verifier first verifies a new event wrt to the delegate's latest event KEL sequence and digest and then lookups to see if there is a delegating seal in the Delegator's KEL. It does not care if there happens to be other copies of that very same delegating seal in other events in the delegator's KEL. Any one would satisfy its verification logic. It just needs one.

To reiterate, from a security perspective it doesn't appear to matter if there is more than one delegating event. Any one of the events is sufficient to authorize the delegation. The number or order of delegating events doesn't appear to matter as long as there is at least one. They all make the identical commitments to the very same delegated event.

There may be an odd corner case where the delegated event anchors do not appear in the same order in the delegator's KEL as they appear in the delegate's KEL. I don't think this matters. The ordering that is authoritative is the delegate's KEL not the delegator's. Moreover, a malicious delegator can't predict a future rotation event in the delegate's KEL because it doesn't know the delegate's pre-rotated keys. So the corner case would only happen if the delegate created multiple delegated event requests close together and the delegator processed them asynchronously in that is verified them in one processing order (which would have to be the delegated KEL order or they would not verify) but then anchored them in a different order in its delegating KEL. The first seen rule of a verifier when verifying the delegate's KEL means the verifier won't see a delegated KEL event if it hasn't yet been anchored in the delegator's KEL and it can look it up. So it will only verify in the delegated KELs ordering not the looked up anchor ordering since it doesn't care when or where it appeared in the delegating KEL just that it has already appeared by the time it does the lookup to verify and it knows how to find it.

A malicious delegator that knows the delegate's pre-rotated keys may create any delegations it wants any way. So it's no loss that I can see. Changing the order of delegating seals in the Delegator's KEL does not change the order of the delegated event in the Delegate's KEL. All the verifiable delegating seals commit to the same event ordering in the Delegate's KEL. Any verifier is still protected by the first seen duplicity detection rule.

Proposed change

Currently the location seal in the delegated event commits the delegate to a unique event in the delegator's KEL. But as explained above there does not appear to be a good security reason why any delegating seal in not equivalent. (This by the way, was the reasoning that arose out of examining the security posture of TELs). Any verifier has to commit to one first seen version of the Delegator's KEL and one first seen version of the Delegate's KEL. KERI is not currently imposing any ordering requirements on the order of appearance of delegating seals. Just that the the one pointed to by the Delegated event can be found. But we could point to it with an attachment instead.

In other words, now that we have complex attachments we can simplify the KERI delegated events by replacing in the delegated event, the delegating location seal with the delegator's identifier prefix and then attach the delegating event sequence number and the delegating event digest to the delegated event as an attachment.

This has two performance advantages:

The new proposed delegated events are as follows:

Delegated Inception

{
    "v" : "KERI10JSON00011c_",
    "i" :  "EJJR2nmwyYAfSVPzhzS6b5CMZAoTNZH3ULvaU6Z-i0d8",
    "s" : "0",
    "t" :  "dip",
    "kt":  "1",
    "k" :  ["DaU6JR2nmwyZ-i0d8JZAoTNZH3ULvYAfSVPzhzS6b5CM"],
    "n" :  "EZ-i0d8JZAoTNZH3ULvaU6JR2nmwyYAfSVPzhzS6b5CM",
    "wt":  "1",
    "w" : ["DTNZH3ULvaU6JR2nmwyYAfSVPzhzS6bZ-i0d8JZAo5CM"],
    "c" :  ["DND"],
    "a" : [],
    "di" :"EZAoTNZH3ULvaU6Z-i0d8JJR2nmwyYAfSVPzhzS6b5CM"
}

Attached to the event is a new hetero attachment group with delegating event sequence number and digest.

di is the compact label for delegator identifier prefix. This is the same label used in the key state message.

Delegated Rotation

{
    "v" : "KERI10JSON00011c_",
    "i" :  "EZAoTNZH3ULvaU6Z-i0d8JJR2nmwyYAfSVPzhzS6b5CM",
    "s" : "1",
    "t" :  "drt",
    "p" : "EULvaU6JR2nmwyZ-i0d8JZAoTNZH3YAfSVPzhzS6b5CM",
    "kt" :  "1",
    "k"  :  ["DaU6JR2nmwyZ-i0d8JZAoTNZH3ULvYAfSVPzhzS6b5CM"],
    "n"  :  "EYAfSVPzhzZ-i0d8JZAoTNZH3ULvaU6JR2nmwyS6b5CM",
    "wt":  "1",
    "wa":  ["DTNZH3ULvaU6JR2nmwyYAfSVPzhzS6bZ-i0d8JZAo5CM"],
    "wr":   ["DH3ULvaU6JR2nmwyYAfSVPzhzS6bZ-i0d8TNZJZAo5CM"],
    "a" : [ ],
    "di" : "EZAoTNZH3ULvaU6Z-i0d8JJR2nmwyYAfSVPzhzS6b5CM"
}

Attached to the event is a new hetero attachment group with delegating event sequence number and digest.

di is the compact label for delegator identifier prefix. This is the same label used in the key state message.

stevetodd commented 3 years ago

It's my understanding that delegated identifiers can only have delegated rotations and that the delegator can't be changed. Is that right? If so, is there a reason we need to keep "di" in delegated rotations? It seems like we only need to keep it in inception events.

SmithSamuelM commented 3 years ago

It is true that the delegator may not be changed. So having the di in the rotation event may be redundant.

My biggest concern is that one of the not yet implemented features of delegated identifiers which is described in the white paper in the Section 11.6.1 Nested Delegation Recovery is the the recovery of compromised delegated pre-rotated keys. This is allowing the case where an attacker not only compromises the signing keys but also the pre-rotated keys of the delegate. The attacker could create rotations in a delegate's KEL that once recovered may be much more difficult to reconcile securely by a validator. They already are more difficult because one has to walk up the delegation tree to find a clean delegation. What I mean by clean would take some effort to describe. I would want to work through the attack vectors of nested pre-rotated recovery with out di in the rotation event first, so I am reluctant to remove the commitment before that.

But if I get some time to think about it more I will consider it. It is definitely needed in the inception event but the rotation event via its prior digest to the prior event and that event to its prior and so on back to the inception is making an indirect commitment to the di in the inception. Both the rotation (and interaction events) are making indirect backwards commitments to the "di" in the inception event and the interaction event already does not have a di field (but interaction events do not change keys so their security posture is different) so it may only be needed in the inception event. But I am not sure it can be removed.

SmithSamuelM commented 3 years ago

But having complex hetero attachments is allowing a rethinking of the existing key events. So worthwhile suggestion.

SmithSamuelM commented 3 years ago

I couldn't find a reason to keep the di field in the drt event. Every time I tried to come up with an exploit the prior digest field commitment chain to the inception thwarted it.

Delegated Inception

{
    "v" : "KERI10JSON00011c_",
    "i" :  "EJJR2nmwyYAfSVPzhzS6b5CMZAoTNZH3ULvaU6Z-i0d8",
    "s" : "0",
    "t" :  "dip",
    "kt":  "1",
    "k" :  ["DaU6JR2nmwyZ-i0d8JZAoTNZH3ULvYAfSVPzhzS6b5CM"],
    "n" :  "EZ-i0d8JZAoTNZH3ULvaU6JR2nmwyYAfSVPzhzS6b5CM",
    "wt":  "1",
    "w" : ["DTNZH3ULvaU6JR2nmwyYAfSVPzhzS6bZ-i0d8JZAo5CM"],
    "c" :  ["DND"],
    "a" : [],
    "di" :"EZAoTNZH3ULvaU6Z-i0d8JJR2nmwyYAfSVPzhzS6b5CM"
}

Attached to the event is a new hetero attachment group with delegating event sequence number and digest.

di is the compact label for delegator identifier prefix. This is the same label used in the key state message.

Delegated Rotation

{
    "v" : "KERI10JSON00011c_",
    "i" :  "EZAoTNZH3ULvaU6Z-i0d8JJR2nmwyYAfSVPzhzS6b5CM",
    "s" : "1",
    "t" :  "drt",
    "p" : "EULvaU6JR2nmwyZ-i0d8JZAoTNZH3YAfSVPzhzS6b5CM",
    "kt" :  "1",
    "k"  :  ["DaU6JR2nmwyZ-i0d8JZAoTNZH3ULvYAfSVPzhzS6b5CM"],
    "n"  :  "EYAfSVPzhzZ-i0d8JZAoTNZH3ULvaU6JR2nmwyS6b5CM",
    "wt":  "1",
    "wa":  ["DTNZH3ULvaU6JR2nmwyYAfSVPzhzS6bZ-i0d8JZAo5CM"],
    "wr":   ["DH3ULvaU6JR2nmwyYAfSVPzhzS6bZ-i0d8TNZJZAo5CM"],
    "a" : [ ]
}
chunningham commented 3 years ago

This change will simplify the delegation procedure greatly by removing the interactive component of trading location seal data between delegator and delegate. The only concern could be weakening the security model by removing a direct commitment from the event packet, however IMO there is no difference actually as the delegator is still committed to in the DIP event and the location seal used previously did not have a digest commitment to the delegating event anyway due to hash-bootstrapping issue inherent in hash links. In the absolute worst-case where the attachment is lost, a validator can still search the delegator KEL for the seal of the DIP event.

SmithSamuelM commented 3 years ago

Here is a suggestion for how we can be more precise in our terminology: I used this terminology for the RAET protocol which is much more complex than what we have so far for KERI (RAET is a transaction protocol that includes multiple segment per message that may be encrypted and signed)

Each message has a head (or header), body, and foot (or footer) In KERI we do not have headers (yet?) but we do have a message body (that is the serialized signed portion of a message) and a message foot that is composed of all the attachments (each attachment is a footer). The message body plus the message foot is the message.

So body is a map structure (python dict, javascript object, rust structure) that is serialized as a unit (JSON, CBOR, MGPK). Attached to the body is a foot. The version of the message (body plus foot) is provided by the version string in the body. In the future when we say message it means that whole message body and foot. But when not confusing could merely mean the message body. When potentially confusing then qualify as message body.