lio- Labeled IO Information Flow Control Library

Safe HaskellTrustworthy




This module provides two functions useful for delegating privileges. The delegate function creates a Priv value less powerful than an existing one. Gates provide a mechanism for authenticating calls to closures that embed privileges.


Delegating privileges

delegate :: SpeaksFor p => Priv p -> p -> Priv pSource

delegate allows you to create a new privilege object that is less powerful than an existing privilege object. The first argument supplies actual privileges. The second argument is a PrivDesc describing the desired new privileges. The call throws an exception unless the privileges supplied speaksFor the privileges requested.

Note: If you are looking for a way to create privileges more powerful than ones you already have, you can use the mappend function to combine existing privileges.


LIO provides a basic implementation of gates, useful in providing controlled RPC-like services where the client and service provider are in mutual distrust.

A service provider uses gate to create a gate data type Gate p a given a computation of type p -> a. Here, p is a privilege description (type variable for an instance of PrivDesc). Gates are invoked with callGate, and as such the service provider has the guarantee that the client (the caller) owns the privileges corresponding to the privilege description p. In effect, this allows a client to "prove" to the service provider that they own certain privileges without entrusting the service with its privileges. The gate computation can analyze this privilege description before performing the "actual" computation. The client and server solely need to trust the implementation of callGate.

data Gate p a Source

A Gate is a lambda abstraction from a privilege description to an arbitrary type a. Applying the gate is accomplished with callGate which takes a privilege argument that is converted to a description before invoking the gate computation.




:: (p -> a)

Gate computation

-> Gate p a 

Create a gate given a computation from a privilege description. Note that because of currying type a may itself be a function type and thus gates can take arguments in addition to the privilege descriptoin.



:: Gate p a


-> Priv p

Privilege used as proof-of-ownership

-> a 

Given a gate and privilege, execute the gate computation. It is important to note that callGate invokes the gate computation with the privilege description and NOT the privilege itself.

Note that, in general, code should not provide privileges to functions other than callGate when wishing to call a gate. This function is provided by LIO since it can be easily inspected by both the gate creator and caller to be doing the "right" thing: provide the privilege description corresponding to the supplied privilege as "proof" without explicitly passing in the privilege.

Gate example

This example uses LIO.DCLabel to demonstrate the use of gates. The service provider provides addGate which adds two integers if the gate is called by a piece of code that owns the "Alice" or "Bob" principals. Otherwise, it simply returns Nothing. Though privInit (in LIO.Run) allows us to create arbitrary privileges in the IO monad, the gate restricts access to addGate from within the LIO monad where code cannot create arbitrary privileges.

 import LIO
 import LIO.DCLabel
 import LIO.Run
 -- | Add two numbers if the computation is invoked by Alice or Bob.
 addGate :: Gate CNF (Int -> Int -> Maybe Int)
 addGate = gate $ \pd a b ->
   if pd `speaksFor` "Alice" \/ "Bob"
   then Just $ a + b
   else Nothing
 main :: IO ()
 main = do
   alice <- privInit $ toCNF $ "Alice"
   bob <- privInit $ toCNF $ "Bob"
   clark <- privInit $ toCNF $ "Clark"
   putStrLn . show $ [
       callGate addGate alice 1 2 -- Just 3
     , callGate addGate bob   3 4 -- Just 7
     , callGate addGate clark 5 6 -- Nothing