If we foil the previous attack by implementing wrap/unwrap directly in terms of seal/unseal, Alice could still fool Bob into blaming Carol for bad service provided by Alice. ? pragma.syntax("0.9") Changed from the framing-bob code so that A will print a naughty word when asked to hi(), thereby providing bad service. ? def c { > to hi() { > println("hi") > } > to beEvil() { > println("a bad word") > } > } # value: <c> ? c.hi() # stdout: hi # ? c.beEvil() # 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() { > c.beEvil() > } > to hi() { # ADDED! > println("a naughty word") > } > } > return a > } # value: <makeA> ? def directA := makeA(b, c) # value: <a> ? directA.start() # stdout: hi # ? directA.badStart() # stdout: a bad word # ? directA.hi() # stdout: a naughty word # The only change from the nary original is to simplify the wrap/unwrap functions to simply call Bob's seal/unseal directly, in order to foil the attack which identity functions allow: # 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, whoBob, _) { # CHANGED! return whoBob.seal(s3) } def unwrap(gs3, _, beBob) { # CHANGED! return beBob.unseal(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 # Unchanged from the framing-bob scenario: ? a.badStart() # stdout: Alice said: # > I ask Carol to: # > > beEvil/0 # Carol said: # > Alice asks me to: # > > beEvil/0 # a bad word # Now how can and can't things go wrong? Previous Attack FoiledExcept for the changed comment, this is unchanged from the framing-bob scenario: # 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 of the above changes, this step now fails CHANGED! 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 } Except for the difference in outcome, this is unchanged from the framing-bob scenario: ? 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 # # problem: <NoSuchMethodException: <a SealedBox>.deliver/2> The attack fails because gs3 is now a sealed box which can only be unsealed using BeBob, which Alice doesn't have. New Attack!In this attack, Alice overrides how her P1 proxy handles the P2 argument of the foo/1 message sent by her A object. This P2 argument represents Alice's access to Carol's C object. Alice instead sends to Bob an object (directA) that , when Bob asks it to hi/0, will instead print a naughty word, thereby providing bad service to Bob. (A proper example should provide bad service which is observably bad by Bob. This is easily if tediously done within this framework.) Although Alice is the one providing bad service to Bob, Alice has fooled Bob into blaming Carol for providing him bad service. (Or would, if the badness were observable by Bob.) # E sample def makeNaughtyProxy(whoBlame, stub, reportln, fauxS2) { def log := makeQuoteln(reportln, `I ask ${whoBlame.getBrand()} to:`, 75) def naughtyProxy extends makeProxy(whoBlame, stub, reportln) { to foo(p2) { log(`foo/1`) def [s2, whoCarol] := p2.getGuts() def gs3 := fauxS2.intro(whoBlame) def p3Desc := [gs3, whoCarol] stub.deliver("foo", [p3Desc]) } } return naughtyProxy } def makeNaughtyPrincipal(label :String, fauxC) { def reportln := makeQuoteln(println, `$label said:`, 77) def [whoMe, beMe] := makeBrand(label) def naughtyPrincipal { 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) def fauxS2 := makeStub(beMe, whoMe, fauxC, reportln) return makeNaughtyProxy(whoBlame, stub, reportln, fauxS2) } } return naughtyPrincipal } Being naughty is like being bad, except that we provide as an extra parameter which object to use to provide bad service, rather than who to frame. ? def naughtyAlice := makeNaughtyPrincipal("NaughtyAlice", directA) # value: NaughtyAlice ? def naughtyGS1 := bob.encodeFor(b, naughtyAlice.who()) ? def naughtyGS2 := carol.encodeFor(c, naughtyAlice.who()) ? def naughtyP1 := naughtyAlice.decodeFrom(naughtyGS1, bob.who()) ? def naughtyP2 := naughtyAlice.decodeFrom(naughtyGS2, carol.who()) ? def naughtyA := makeA(naughtyP1, naughtyP2) ? naughtyA.start() # stdout: NaughtyAlice said: # > I ask Bob to: # > > foo/1 # NaughtyAlice said: # > NaughtyAlice asks me to: # > > meet Bob # Bob said: # > NaughtyAlice asks me to: # > > foo/1 # Bob said: # > I ask Carol to: # > > hi/0 # NaughtyAlice said: # > Bob asks me to: # > > hi/0 # a naughty word # Although Bob thinks he asked Carol to hi/0, a naughty word got printed, which Carol wouldn't do. |
||||||||||||
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
|