[E-Lang] Hash Chaining & Capabilities, Proposal #2d: Deputizing Remote
Vats
Mark S. Miller
markm@caplet.com
Sat, 11 Nov 2000 08:44:55 -0800
Here is the long delayed next step in this proposal for Capability-based
Active Invocation Certificates. For an indefinitely postponed hypothetical
piece of engineering, this thread is taking up a distressing amount of
paper. *If* off-line certificates are indeed useful in an increasingly
on-line world (a questionable assumption), then I believe this thread will
prove important. Thanks for your indulgence.
(Alan and Bill, you guys are the most qualified to address this
questionable assumption, as you've both been heavily involved in engineering
efforts with similar goals on both sides of this coin. (E-Speak 2.2 vs
E-Speak 3.0/SPKI; Indra & Pluribus vs SPKI). Is there a compelling
need for off-line certificates? Do they address a real problem?)
Previous messages in this thread have already established a strong
correspondence between Invocation Certificates and E/Pluribus messages --
they are simply the off-line and on-line embodiments, respectively, of a
Granovetter/capability message. The semantic differences are only due to
the differences between our notions off-line and on-line (significantly
clarified in answer to Bill's question), plus that we only define off-line
certificates to be the equivalent of sendOnly messages -- messages without a
continuation
http://www.erights.org/elib/concurrency/msg-passing.html#sendOnly .
The remaining element, and the element that motivated this whole thread in
the first place, is the not-yet-explained "Active" feature of our
certificate proposal. Rather than explain Active certificates directly,
this message will show the on-line equivalent of this feature:
Deputizing Remote Vats with Mobile Code. That's why we introduced the
Evaluator earlier.
Let's construct the standard deputy scenario
http://www.erights.org/elib/capability/deputy.html . Let's say that Alice
had a prior reference to Mallet and the power, P, and that Alice constructs
Bob in order to provide Mallet with reduced authority over the power. For
example, let's say P is a mutable slot with getValue() and
setValue(newValue) messages, and that Alice wishes to provide Mallet only
the authority to see the current value, but not to set it. As a contrived
embellishment whose purpose will be clear later, let's say Alice constructs
Bob to accept but ignore the setValue message. Alice might define Bob thus:
define BobMaker new(P) :any {
define Bob {
to getValue :any { P getValue }
to setValue(newValue) {}
}
}
Alice would then give Mallet
Mallet foo(BobMaker new(P))
However, now let's say Alice, P, and Mallet are all in three separate vats:
VatA, VatP, and VatM. The code would then read
define BobMaker new(P) :any {
define Bob {
# returns a promise for the value
to getValue :any { P <- getValue }
to setValue(newValue) {}
}
}
Mallet <- foo(BobMaker new(P))
>From a security point of view, this is ideal. Bob is Alice's deputy, and
Bob runs on VatA, and therefore Alice's TCB. Alice necessarily
"trusts" her own TCB, not because she necessarily has higher confidence in
its trustworthiness, but because she can't help but be fully vulnerable to
it, so she may as well stop worrying. Since she already has this
vulnerability, she does not acquire any new vulnerability by trusting the
same TCB to run Bob.
Unfortunately, depending on the particulars of the situation, this choice
may not be ideal from a distributed systems point of view. Any time Mallet
wishes to exercise his reduced power, the request has to go through Bob
(necessary) and therefore through VatA (unfortunate). Besides the obvious
performance cost, Alice may be expecting VatA to go off-line soon, or become
otherwise inaccessible to VatM and VatP. Let's say Alice also expects VatM
and VatP to remain accessible to each other. If Alice were introducing
Mallet to all of P, our standard Granovetter introduction protocol would put
VatM and VatP in direct contact, and Alice could drop out of the picture
without disrupting their further communication. How can Alice introduce
Mallet to the "some of P" represented by Bob, and still be able to drop out?
I'm sure you can all see what's coming: there are only two other Vats in the
picture. Alice's only two sensible choices are to instantiate Bob on VatM
or on VatP. Both subject Alice to greater security risk that Bob on VatA.
Bob on VatM:
If Alice trusts VatM more than Mallet, this can be a sensible choice
(depending on the nature of trust in VatM). Alice cannot rationally trust
VatM less than Mallet. If she trusts them the same, then this is a bad
choice, since VatM is being given direct access to P.
Bob on VatP:
P is necessarily vulnerable to VatP, so any dishonest execution of Bob
that's equivalent to corruption of P creates no loss of security. What
greater damage can a corrupt VatP cause? Alice's intended Bob behavior
prevents Mallet from sending capabilities to P as argument of setValue
message. Is this a form of distributed capability confinement
http://www.erights.org/elib/capability/dist-confine.html ? With Bob on
VatA, it might seem that Mallet and P cannot arrange for Mallet to send
capabilities to P. Unfortunately, the getValue message, as currently
defined, allows P to "send" (reveal, as the outcome of a prior send) an
arbitrary capability, which is enough to work around the restriction.
However, Bob might be more constraining. A Bob that only allowed integers
to be gotten from P would prevent Mallet from sending a capability to P.
If we run Bob on VatP and VatP is corrupt (and in cahoots with Mallet and
P), then it can give to P capabilities from Mallet that Alice coded Bob to
prevent. But wait a second, if VatP is corrupt, can't it separately
establish a channel between Mallet and P? Only with VatM's cooperation. So
we're back to relying on trust in VatM.
When the location question comes up, I suspect capability confinement will
rarely be a concern (though it's good to check!). Therefore, when
non-security issues argue against putting Bob on VatA, security issues will
typically argue for putting it on VatP. Note that the non-security issues
are almost perfectly indifferent between VatP and VatM.
Ok, so how does Alice instantiate Bob on VatP, and give Mallet access to
that Bob. An economist turned programmer might say "Assume an Evaluator"
http://www.erights.org/javadoc/org/erights/e/elang/evm/Evaluator.html .
Specifically, an Evaluator on VatP (exported by VatP's TCB), let's say
called evalP in Alice's scope. Alice only needs to change her code to:
meta <- eval(evalP, define BobMaker new(P) :any {
define Bob {
# returns a promise for the value
to getValue :any { P <- getValue }
to setValue(newValue) {}
}
})
Mallet <- foo(BobMaker <- new(P))
This asks the Evaluator on VatP to evaluate the expression defining
"BobMaker". It also defines "BobMaker" in this (Alice's) scope to be a
promise for that remote BobMaker. We then send a remote request on this
BobMaker-promise to create a new Bob (BobMaker <- new(P)). The value of
this expression is a promise for Bob, which is then sent to Mallet.
(Just to show off message pipelining
http://www.erights.org/elib/concurrency/pipeline.html , all three of these
messages go out immediately, without VatA waiting to hear anything back.)
The analogy with the SPKI subsetting language should be clear: Bob expresses
a subsetting of the authority of P. Alice, who has authority P, is giving
Mallet only that subset, but is handing over the interpretation of her
subsetting intentions to VatP. When Mallet goes to exercise his authority,
the subsetting is enforced by VatP, hopefully according to Alice's
instructions.
The main difference, due to Nikita, is that we're expressing the subsetting
in a general purpose programming language. This allows abstraction as well
as subsetting-by-thinning. For example, a covered call option is a deputy
subsetting-by-abstraction the underlying instrument, such as stock. One could
never express this kind of subsetting in a data-language such as SPKI provides.