ERights Home elib / capability / horton 
Back to: Handling N Arguments On to: Alice Frames Carol

Alice Frames Bob


If Horton's wrap/unwrap functions were instead simple identity functions, then Alice could fool Carol into blaming Bob for messages sent by Alice.
? pragma.syntax("0.9")

Changed from the nary original so that C can also be asked to be evil, and so that A can ask its c to be evil.

? def c {
>     to hi() {
>         println("hi")
>     }
>     to beEvil() {                   # ADDED!
>         println("a bad word")
>     }
> }
# value: <c>
 
? c.hi()
# stdout: hi
#
 
? c.beEvil()                          # ADDED!
# stdout: a bad word
#
 
? def b {
>     to foo(c) {
>         c.hi()
>     }
> }
# value: <b>
 
? b.foo(c)
# stdout: hi
#
 
? def makeA(b, c) {
>     def a {
>         to start() {
>             b.foo(c)
>         }
>         to badStart() {            # ADDED!
>             c.beEvil()
>         }
>     }
>     return a
> }
# value: <makeA>
 
? def directA := makeA(b, c)
# value: <a>
 
? directA.start()
# stdout: hi
#
 
? directA.badStart()                 # ADDED!
# stdout: a bad word
#

The only change from the nary original is to simplify the wrap/unwrap functions to be identity functions:

# E sample
 
def makeQuoteln := <elang:interp.makeQuoteln>
 
def makeProxy(whoBlame, stub, reportln) {
    def log := makeQuoteln(reportln,
                           `I ask ${whoBlame.getBrand()} to:`,
                           75)
    def proxy {
        to getGuts() {
            return [stub, whoBlame]
        }
        match [verb, args] {
            log(`$verb/${args.size()}`)
            var pDescs := []
            for p2 in args {
                def [s2, whoCarol] := p2.getGuts()
                def gs3 := s2.intro(whoBlame)
                def p3Desc := [gs3, whoCarol]
                pDescs with= p3Desc
            }
            stub.deliver(verb, pDescs)
        }
    }
    return proxy
}
 
def wrap(s3, _, _) {             # CHANGED!
    return s3
}
 
def unwrap(gs3, _, _) {          # CHANGED!
    return gs3
}
 
def makeStub(beMe, whoBlame, targ, reportln) {
    def log := makeQuoteln(reportln,
                           `${whoBlame.getBrand()} asks me to:`,
                           75)
    def stub {
        to intro(whoBob) {
            log(`meet ${whoBob.getBrand()}`)
            def s3 := makeStub(beMe,whoBob,targ,reportln)
            return wrap(s3, whoBob, beMe)
        }
        to deliver(verb, pDescs) {
            log(`$verb/${pDescs.size()}`)
            var args := []
            for p3Desc in pDescs {
                def [gs3, whoCarol] := p3Desc
                def s3 := unwrap(gs3, whoCarol, beMe)
                def p3 := makeProxy(whoCarol, s3, reportln)
                args with= p3
            }
            E.call(targ, verb, args)
        }
    }
    return stub
}

Unchanged from the original:

# E sample
 
def makeBrand := <elib:sealing.makeBrand>
 
def makePrincipal(label :String) {
    def reportln := makeQuoteln(println, `$label said:`, 77)
    def [whoMe, beMe] := makeBrand(label)
    def principal {
        to __printOn(out :TextWriter) {
            out.print(label)
        }
        to who() {
            return whoMe
        }
        to encodeFor(targ, whoBlame) {
            def stub := makeStub(beMe, whoBlame, targ, reportln)
            return wrap(stub, whoBlame, beMe)}
        to decodeFrom(gift, whoBlame) {
            def stub := unwrap(gift, whoBlame, beMe)
            return makeProxy(whoBlame, stub, reportln)
        }
    }
    return principal
}

Unchanged from the original:

? def alice := makePrincipal("Alice")
# value: Alice
 
? def bob := makePrincipal("Bob")
# value: Bob
 
? def carol := makePrincipal("Carol")
# value: Carol

Unchanged from the original:

? def gs1 := bob.encodeFor(b, alice.who())
 
? def gs2 := carol.encodeFor(c, alice.who())
 
? def p1  := alice.decodeFrom(gs1, bob.who())
? def p2  := alice.decodeFrom(gs2, carol.who())
? def a := makeA(p1, p2)

Unchanged from the nary original:

? a.start()
# stdout: Alice said:
#         > I ask Bob to:
#         > > foo/1
#         Carol said:
#         > Alice asks me to:
#         > > meet Bob
#         Bob said:
#         > Alice asks me to:
#         > > foo/1
#         Bob said:
#         > I ask Carol to:
#         > > hi/0
#         Carol said:
#         > Bob asks me to:
#         > > hi/0
#         hi
#

In the following example, Carol properly records that Alice is the one that asked her to be evil, and Alice properly records that Carol is the one she'll blame if evil does not happen as requested.

? a.badStart()
# stdout: Alice said:
#         > I ask Carol to:
#         > > beEvil/0
#         Carol said:
#         > Alice asks me to:
#         > > beEvil/0
#         a bad word
#

This shows everything works as it's supposed to. But how can things go wrong?


Attack!

BadAlice is like Alice, except that when her proxy (P2) is asked (by A) to beEvil(), rather than sending the message to s2, which will cause Carol to properly blame Alice as shown above, Alice instead asks Carol to make a stub (S3) for Bob's use. BadAlice then uses this stub directly, succesfully fooling Carol into blaming Bob for asking her to be evil.

# E sample
 
def makeBadProxy(whoBlame, stub, reportln, whoFrame) {
    def log := makeQuoteln(reportln,
                           `I ask ${whoBlame.getBrand()} to:`,
                           75)
    def badProxy extends makeProxy(whoBlame, stub, reportln) {
        to beEvil() {
            log(`beEvil/0`)
            def gs3 := stub.intro(whoFrame)
            # because wrap is an identity function, gs3 is simply stub S3.
            gs3.deliver("beEvil", [])
        }
    }
    return badProxy
}
 
def makeBadPrincipal(label :String, whoFrame) {
    def reportln := makeQuoteln(println, `$label said:`, 77)
    def [whoMe, beMe] := makeBrand(label)
    def badPrincipal {
        to __printOn(out :TextWriter) {
            out.print(label)
        }
        to who() {
            return whoMe
        }
        to encodeFor(targ, whoBlame) {
            def stub := makeStub(beMe, whoBlame, targ, reportln)
            return wrap(stub, whoBlame, beMe)}
        to decodeFrom(gift, whoBlame) {
            def stub := unwrap(gift, whoBlame, beMe)
            return makeBadProxy(whoBlame, stub, reportln, whoFrame)
        }
    }
    return badPrincipal
}

Now we need to set up new initial conditions with BadAlice in place of Alice. For this example, we can reuse our existing Bob and Carol, since they are memoryless and don't depend on Alice.

? def badAlice := makeBadPrincipal("BadAlice", bob.who())
# value: BadAlice
 
? def badGS1 := bob.encodeFor(b, badAlice.who())
 
? def badGS2 := carol.encodeFor(c, badAlice.who())
 
? def badP1  := badAlice.decodeFrom(badGS1, bob.who())
? def badP2  := badAlice.decodeFrom(badGS2, carol.who())
? def badA := makeA(badP1, badP2)
 
? badA.badStart()
# stdout: BadAlice said:
#         > I ask Carol to:
#         > > beEvil/0
#         Carol said:
#         > BadAlice asks me to:
#         > > meet Bob
#         Carol said:
#         > Bob asks me to:
#         > > beEvil/0
#         a bad word
#

Although Bob never asked anyone to beEvil(), and in fact contains no code which could, Carol nevertheless records that Bob asked her to be evil.

 
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
ERights Home elib / capability / horton 
Back to: Handling N Arguments On to: Alice Frames Carol
Download    FAQ    API    Mail Archive    Donate

report bug (including invalid html)

Golden Key Campaign Blue Ribbon Campaign