[E-Lang] Hash Chaining & Capabilities, Proposal #2b:
Off-Line Invocation Certificates
Mark S. Miller
markm@caplet.com
Wed, 18 Oct 2000 14:23:17 -0700
Message vs Invocation:
A Terminology Correction.
In the previous note, when I referred to "Message" I usually should have
said "Invocation". An invocation is a pair of a Message and a reference to
the object that will receive the Message -- the Recipient. In the
Granovetter diagram, the fat arrow is a Message containing a reference to
Carol as an argument. The fat Message arrow combined with the thin reference
arrow on which it rides -- the reference to Bob -- together constitute an
Invocation. With these definitions, it is clear that an authorization
certificate represents an Invocation Argument rather than a Message
Argument, since it authorizes only the Recipient.
The canonical example is a certificate from Alice authorizing Bob to invoke
Carol. If it were a Message Argument, then it would authorize whoever the
Message were sent to, without that having been determined yet.
Why we need off-line Invocations, not just off-line Arguments:
Another Lesson from the Confused Deputy
The punch line we all know from the Confused Deputy paper is "Don't separate
designation from authority." But this paper has enough punch lines to last
a conventional lifetime. Here's another.
Let's define authorization as the granting of authority. One may conclude
from the same tale that, even if designation and authority are kept
together, "one must not separate authorization from invocation". Why? In a
normal message-based capability system, the deputy only receives new
authority as arguments of messages he receives asking him to do something.
Each new authority has a separate position in the request, which represents
its intended role in this request. Only this context information gives the
Deputy enough information to know what to do and what NOT to do with the new
authority he's just been granted.
When authorization is communicated without such context, it's like receiving
a key in the mail with no hint about what to do with it. Or it's like an
object system in which objects respond to the message
hereIsSomethingYouMayFindUseful(arg)
After an object receives this message, she can invoke arg if she chooses,
but why would she ever choose to do so? Were the separation of
authorization from invocation truly this silly, no one would have thought to
separate them. Instead, no one seems to question separating them. Why? I
can think of two reasons, both derived from the ACL paradigm:
1) Ambient Authority. The following chain of reasoning seems very
plausible, especially if it's not articulated or examined closely: If
object A attempts to perform action X, and object A has enough authority to
perform action X, then object A's attempt to perform action X should be be
permitted. The implicit assumption is that, if A attempts X, then A must
want to perform X. If it wants to and it's allow to, clearly it should be
permitted to. In such a system, a hereIsSomethingYouMayFindUseful() message
could simply add arg to the object's ambient authority.
The flaw is the assumption that it wants its attempt to succeed. A deputy
only brings to bear on an action those authorities that should be applied to
the action, because it wishes the action to fail if these authorities are
inadequate -- even if the deputy itself has further authority. How does a
deputy determine which authorities to apply to an action? In a capability
system, only according to how the deputy came to hold these authorities --
by initial endowment and by receiving them as invocation arguments.
2) Labelling. In SPKI, an authorization certificate not only authorizes, it
names the resources that it authorizes access to. It's like receiving a key
in the mail that's labelled with the name of the thing it opens. This
presumes a namespace that's meaningful among the various parties,
necessitating that we solve a harder problem before we can solve the easier
problem. Our invocation perspective is much like the labelling perspective:
the message carries a message name (in E, the verb) used by the receiver to
understand why he's receiving the arguments. However, the verb labels the
reason for interacting, not the resource being authorized. The latter needs
no name -- the capability is all the designation we need, and all the
designation we can trust.
Of course, once Alice is invoking Bob rather than just authorizing Bob, now
Bob, like Carol, is something to be invoked. Just as Alice or Bob must be
authorized in order to invoke Carol, so must Alice be authorized to invoke
Bob. If invoking is the only means of authorizing, then Alice must be
authorized to invoke Bob in order for Alice to be able to authorize Bob. In
situations where this is enforceable, this both provides the reference arrow
missing from http://www.erights.org/elib/capability/ode/images/spki.gif and
removes the asymmetry between Subject and Resource. Both would simply be
objects, and shown as circles. The full Granovetter diagram would be restored.
The Parts of an Invocation in E
So let's examine and give names to all the parts of an inter-vat Invocation
in E. Inter-vat Invocations in E may only be asynchronous, so we examine
only the eventual ("<-") send expression:
recipient <- verb(args...)
which acts like two different expressions depending on context:
a) define result := recipient <- verb(args...)
b) recipient <- verb(args...); null
Both of these asks the recipient to eventually perform the verb-named action
using the provided arguments. The request is queued on the vat of the
recipient to be performed to completion when that vat is done with all prior
requests.
#a is the general case: When the send expression occurs in a static context
where its value is needed (evaluated for value), the send expression
immediately returns a promise for the outcome of performing the request.
This is a tail of a reference arrow whose head is encapsulated in the
Message. (This head serves a role much like a lambda continuation, expect
that it normally provides only data-flow, not control-flow.) We call this
arrowhead the Resolver.
#b is an important optimization: When the send expression occurs in a static
context where the value is not needed (evaluated for effect only), then we
can avoid creating the promise for the return result. In both cases, these
messages are one-way in a control flow sense. #b is also one-way in a
data-flow sense.
So, putting it all together, an E on-line Invocation consists of
Invocation
Recipient (arrowtail)
Message
Verb (usually a String. Always passed by copy.)
Args (List of arrowtails conceptually, but may use any passing mode)
Resolver (optional. arrowhead for reporting outcome)
For off-line invocation certificates, let's tentatively make four semantic
changes.
1) Let's drop the optional Resolver. It's hard to see any motivation for
message pipelining in the off-line case. In the absence of pipelining, most
of the effects of the encapsulated Resolver can instead be provided with an
explicit Resolver argument. This decision does make it awkward to interface
between the on-line and off-line worlds, so we may revisit it later.
2) Drop the requirement of order-preserving fail-stop at-most-once message
delivery. An on-line protocol can provide such guarantees cheaply. For an
off-line protocol, the expense would be too great to put at the foundations.
Instead, we leave it up to the objects interacting via off-line invocations
to deal with the problems resulting from the absence of these guarantees.
I'm quite queasy with this, but it corresponds to the burden placed on the
programmer by any of the other certificate systems. Of course, this make it
yet more awkward to interface the off-line and on-line worlds.
3) Do not provide built-in secrecy. As with the other PKIs, invocation
certificates are signed but not encrypted. If their users wish to
separately encrypt them, fine.
4) Provide built-in non-repudiation and some measure of auditability, at the
price of a further loss of privacy. Indeed, I believe this to be *the*
tradeoff that should determine whether to use a certificate system or a
bearer system. Clearly, both have their place.
Proposed Contents of an E Invocation Certificate
Since we've already got a notation for describing E invocations -- E -- I'll
use it in the certificate proposal below. A more politically acceptable
proposal may use the XML representation of Kernel-E parse trees
http://www.erights.org/elang/kernel/index.html , since this would be less
readable and more verbose. If you wish, consider all the E notation in what
follows to be syntactic sugar for such XML.
As with any lambda language, E expressions are evaluated within a lexical
scope. *.emaker files are evaluated in the E "universal scope" -- a
immutable scope containing only transitively immutable objects that provide
no authority -- such as the binding of "true" to the appropriate boolean.
The expression in our invocation certificate can be evaluated (for effect
only) within this scope, but we needs more. The authorization certificates
provide further capabilities, but only in this context. We need a form of
expression available within this context that wraps the authorization
certificate data and effectively evaluates to the corresponding object
reference.
Let's use E's syntactic sugar for URI expressions, and introduce a binding
for "auth__uriGetter". The expression <auth:...>, with an authorization
certificate in place of the "...", evaluates to a capability to the
authorized object. Ignoring for a moment the issue of whether it evaluates
to an on-line or an off-line reference, our standard example would now look
like:
def bob := <auth:...Alice's authorization (from somewhere) to invoke Bob...>
def carol := <auth:...Bob's authorization from Alice to invoke Carol...>
bob <- foo(carol)
The first authorization would be signed by whoever enabled Alice to invoke Bob.
The second authorization would be signed by Alice, and would include Alice's
authorization to invoke Carol.
The expression as a whole would be signed by Alice.
An Aside: Enabling Stronger Auditing
Should Alice really sign the authorization for Bob to invoke Carol, given
that she's signing the message as a whole? Interestingly, we get much
stronger auditability if the answer is no. If the answer is yes, then this
authorization by itself is what Bob would present when invoking Carol, or
when authorizing someone else to invoke Carol. If the answer is no, then
only this invocation as a whole demonstrates Bob's authorization to Carol.
Likewise, one level back on the chain, Alice's inclusion of the
demonstration that she is authorized to invoke Carol (necessary for her
authorization of Bob to be valid) would not be an authorization certificate,
but rather the entire invocation certificate showing why she came to have
that authority.
If the argument authorizations aren't signed, and therefore don't need to be
standalone, then they also don't need to list the "Subject", since this must
always be the Recipient (Bob). They all must also have the same Issuer
(Alice), so we could list this once rather than per-argument. All that's
left or SPKI's 5-tuple is the Carol designation: <vatID(C),
hash(swissNumber(Carol))>. The authorization data would consist of this
plus a chain of earlier Invocation certificates.
The authorization chains are now more like stack tracebacks, whose utility
for debugging is well known. Auditing and debugging may be more similar
than we think. However, the space overhead may be unreasonable for many uses.
Next Message: I finally get to the "Active" stuff