cpsa-4.4.1: src/CPSA/Roletran/Algebra.hs
-- CPSA4 message terms and their sorts for cpsa4roletran
--
-- This module implements CPSA message algebra terms. In CPSA4, the
-- message algebra is order-sorted. The sorts are text, data, name,
-- skey, akey, mesg, and chan. The sorts text, data, name, skey, and
-- akey are a subsort of mesg. The compiler makes no use of the
-- subsort relation, so it implements the algebra as if it were
-- many-sorted. (The runtime system makes use of the subsort
-- relation.)
--
-- For output, there is a type for each sort, except that there
-- are two types for sort akey, Akey and Ikey. Following the
-- convention on asymmetric key pairs, an asymmetric key is assumed to
-- be public, and therefore has type Akey, if it has the form t or
-- (pubk n), and private, and therefore has type Ikey, if it has the
-- form (invk k) or (privk n).
-- Copyright (c) 2020 The MITRE Corporation
--
-- This program is free software: you can redistribute it and/or
-- modify it under the terms of the BSD License as published by the
-- University of California.
module CPSA.Roletran.Algebra (
Sort(..), Var, Term(..), Skey(..), Akey(..),
sort, inv, isBasic, isMesgVar, isChanVar, VarEnv,
emptyVarEnv, doubleTermWellFormed, carriedBy, receivable) where
import qualified Data.Map.Strict as M
import Data.Map.Strict (Map)
-- The Rust type associated with a variable or a term. We call it the
-- sort because type is a Haskell keyword. A variable is never of
-- sort Ikey.
data Sort
= Text -- Plaintext
| Data -- Data
| Name -- Name
| Skey -- Symmetric key
| Akey -- Public asymmetric key
| Ikey -- Private asymmetric key
| Mesg -- Message -- top sort for terms
| Chan -- Channels -- not allowed
deriving (Show, Eq) -- in terms in events
type Var = String
-- A term. Note that not all terms are well formed. See below for a
-- function that checks for well formedness.
data Term
= Txt Var -- Text variable
| Dta Var -- Data variable
| Nam Var -- Name variable
| Sky Skey -- Symmetric key
| Aky Akey -- Asymmetric key
| Iky Akey -- Inverse asymmetric key
| Msg Var -- Message variable
| Tag String -- A message tag
| Pr Term Term -- A pair of terms,
| En Term Term -- Encryption of a plain text term with a key
| Hsh Term -- Hash of some term
| Chn Var -- Channel variable
deriving (Show, Eq, Ord)
-- Symmetric keys
data Skey
= SVar Var -- Symmetric key variable
| Ltk Var Var -- A long term key associated with two name variables
deriving (Show, Eq, Ord)
-- Asymmetric keys
data Akey
= AVar Var -- Asymmetric key variable
| Pubk Var -- Public key of a name variable
| Pubk2 String Var -- Tagged public key of a name variable
deriving (Show, Eq, Ord)
-- Return the sort of a term.
sort :: Term -> Sort
sort (Txt _) = Text
sort (Dta _) = Data
sort (Nam _) = Name
sort (Sky _) = Skey
sort (Aky _) = Akey
sort (Iky _) = Ikey
sort (Msg _) = Mesg
sort (Tag _) = Mesg
sort (Pr _ _) = Mesg
sort (En _ _) = Mesg
sort (Hsh _) = Mesg
sort (Chn _) = Chan
-- Inverse key
inv :: Term -> Term
inv (Aky k) = Iky k
inv (Iky k) = Aky k
inv t = t
-- Is term a CPSA basic value?
isBasic :: Term -> Bool
isBasic (Txt _) = True
isBasic (Dta _) = True
isBasic (Nam _) = True
isBasic (Sky _) = True
isBasic (Aky _) = True
isBasic (Iky _) = True
isBasic _ = False
-- Is term a CPSA message variable?
isMesgVar :: Term -> Bool
isMesgVar (Msg _) = True
isMesgVar _ = False
-- Is term a CPSA channel variable?
isChanVar :: Term -> Bool
isChanVar (Chn _) = True
isChanVar _ = False
type VarEnv = Map Var Sort
emptyVarEnv :: VarEnv
emptyVarEnv = M.empty
termWellFormed :: VarEnv -> Term -> Maybe VarEnv
termWellFormed env t@(Txt x) =
extendVarEnv env x (sort t) -- Text variable
termWellFormed env t@(Dta x) =
extendVarEnv env x (sort t) -- Data variable
termWellFormed env t@(Nam x) =
extendVarEnv env x (sort t) -- Name variable
termWellFormed env t@(Sky (SVar x)) =
extendVarEnv env x (sort t) -- Symmetric key variable
termWellFormed env (Sky (Ltk x y)) =
-- Long term shared symmetric key
doubleTermWellFormed env (Nam x) (Nam y)
termWellFormed env (Aky k) = -- Asymmetric key terms
akeyWellFormed env k
termWellFormed env (Iky k) = -- Inverse asymmetric key terms
akeyWellFormed env k
termWellFormed env t@(Msg x) =
extendVarEnv env x (sort t) -- Mesg variable
termWellFormed env (Tag _) =
Just env -- Tags
termWellFormed env (Pr x y) =
doubleTermWellFormed env x y -- Pairing
termWellFormed env (En x y) =
doubleTermWellFormed env x y -- Encryption
termWellFormed env (Hsh t) =
termWellFormed env t -- Hashing
termWellFormed env t@(Chn x) =
extendVarEnv env x (sort t) -- Channel variable
-- Extend when sorts agree
extendVarEnv :: VarEnv -> Var -> Sort -> Maybe VarEnv
extendVarEnv env x s =
case M.lookup x env of
Nothing -> Just $ M.insert x s env
Just s' -> if s == s' then Just env else Nothing
akeyWellFormed :: VarEnv -> Akey -> Maybe VarEnv
akeyWellFormed env (AVar x) = extendVarEnv env x Akey
akeyWellFormed env (Pubk x) = extendVarEnv env x Name
akeyWellFormed env (Pubk2 _ x) = extendVarEnv env x Name
doubleTermWellFormed :: VarEnv -> Term -> Term -> Maybe VarEnv
doubleTermWellFormed env x y =
do
env <- termWellFormed env x
termWellFormed env y
-- Is a term carried by another term?
carriedBy :: Term -> Term -> Bool
carriedBy t t' =
t == t' ||
case t' of
Pr x y -> carriedBy t x || carriedBy t y
En x _ -> carriedBy t x
_ -> False
-- Check to make sure a message is receivable. If not, return
-- the offending term.
--
-- A message t is receivable iff
--
-- 1. t contains no occurrence of an encryption in the key of an
-- encryption, and
--
-- 2. t contains no occurrence of an encryption within a hash.
receivable :: Term -> Maybe Term
receivable (Pr x y) =
case receivable x of
Just t -> Just t
Nothing -> receivable y
receivable (En x y) =
case receivable x of
Just t -> Just t
Nothing -> findEnc y
receivable (Hsh x) = findEnc x
receivable _ = Nothing
findEnc :: Term -> Maybe Term
findEnc (Pr x y) =
case findEnc x of
Just t -> Just t
Nothing -> findEnc y
findEnc t@(En _ _) = Just t
findEnc (Hsh x) = findEnc x
findEnc _ = Nothing