Quick actions

cmd+k|ctrl+k

Navigation

Languages

Security type system

Snippet info

Language

Haskell

Visibility

public

Author

rightfold

Created

2018-03-15T20:27:56Z

Updated

2018-03-15T21:28:40Z

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE OverloadedStrings #-}

module Main
  ( main
  ) where

import Control.Comonad (extract)
import Control.Comonad.Cofree (Cofree (..))
import Control.Monad (unless)
import Control.Monad.Error.Class (throwError)
import Data.Map (Map)
import Data.Semigroup ((<>))
import Data.Set (Set)
import Data.Text (Text)

import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.Text.IO as Text.IO

type Environment = Map Text SecurityClass

data Term a
  = Variable Text
  | Assign Text a a
  | If a a a
  deriving (Functor)

type SecurityClass = Set Text

check :: Environment -> Cofree Term () -> Either Text (Cofree Term SecurityClass)
check env (() :< Variable name)
  | Just sc <- Map.lookup name env =
      pure $ sc :< Variable name
  | otherwise = throwError $ "No such variable: " <> name
check env (() :< Assign variable value continuation)
  | Just variableSC <- Map.lookup variable env = do
      value' <- check env value
      let valueSC = extract value'
      unless (valueSC `Set.isSubsetOf` variableSC) $
        throwError $ "Confidentiality violation in Assign: " <>
                       tshow (variable, valueSC, variableSC)
      continuation' <- check env continuation
      let sc = variableSC `Set.union` extract continuation'
      pure $ sc :< Assign variable value' continuation'
  | otherwise = throwError $ "No such variable: " <> variable
check env (() :< If condition consequent alternative) = do
  condition' <- check env condition
  consequent' <- check env consequent
  alternative' <- check env alternative
  let conditionSC = extract condition'
  let consequentSC = extract consequent'
  let alternativeSC = extract alternative'
  unless (conditionSC `Set.isSubsetOf` consequentSC &&
          conditionSC `Set.isSubsetOf` alternativeSC) $
        throwError $ "Confidentiality violation in If: " <>
                       tshow (conditionSC, consequentSC, alternativeSC)
  let sc = consequentSC `Set.intersection` alternativeSC
  pure $ sc :< If condition' consequent' alternative'

prettyTerm :: (a -> Text) -> Cofree Term a -> Text
prettyTerm prettyAnn (ann :< Variable name) =
  name <> "<" <> prettyAnn ann <> ">"
prettyTerm prettyAnn (ann :< Assign variable value continuation) =
  "assign<" <> prettyAnn ann <> "> " <> variable <>
  " := " <> prettyTerm prettyAnn value <>
  ";\n" <> prettyTerm prettyAnn continuation
prettyTerm prettyAnn (ann :< If condition consequent alternative) =
  "if<" <> prettyAnn ann <> "> " <> prettyTerm prettyAnn condition <>
  " then\n" <> indent (prettyTerm prettyAnn consequent) <>
  "\nelse\n" <> indent (prettyTerm prettyAnn alternative) <>
  "\nend"

prettySecurityClass :: SecurityClass -> Text
prettySecurityClass = Text.intercalate ", " . Set.toList

indent :: Text -> Text
indent = Text.intercalate "\n" . fmap ("  " <>) . Text.splitOn "\n"

tshow :: Show a => a -> Text
tshow = Text.pack . show

main :: IO ()
main = do
  example $ variable "a"
  example $ variable "b"
  example $ variable "c"
  example $ if_ (variable "a") (variable "b") (variable "c")
  example $ if_ (variable "a") (variable "c") (variable "d")
  example $ if_ (variable "b") (variable "c") (variable "d")
  where
    variable name = () :< Variable name
    assign name value continuation = () :< Assign name value continuation
    if_ condition consequent alternative = () :< If condition consequent alternative

    example :: Cofree Term () -> IO ()
    example term = do
      Text.IO.putStrLn $ prettyTerm (const "") term
      Text.IO.putStrLn $ ""
      Text.IO.putStrLn . either id (prettyTerm prettySecurityClass) $
        check environment term
      Text.IO.putStrLn $ "---------------"

    environment :: Environment
    environment = Map.fromList
      [ ("a", Set.fromList [])
      , ("b", Set.fromList ["α"])
      , ("c", Set.fromList ["β", "γ"])
      , ("d", Set.fromList ["γ"])
      ]
INFO