-
Notifications
You must be signed in to change notification settings - Fork 1
/
SecurityAnalysis.fs
163 lines (138 loc) · 5.42 KB
/
SecurityAnalysis.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
module SecurityAnalysis
open Interpreter
// Free variables in arithmetic expressions
let fvArith expr =
let (setV, setA) = peekArith expr
Set.union setV setA
// Free variables in boolean expressions
let fvBool expr =
let (setB, setV, setA) = peekBool expr
Set.union setB (Set.union setV setA)
// Function to transform the parsed lattice into a set of flows
let rec buildLattice rawexpr set =
match rawexpr with
| LatFlow(x,y) -> Set.add (x,y) set
| LatDelim(x,y) -> buildLattice x (buildLattice y set)
| _ -> set
// Function to transform the parsed classifications into a map classification
let rec buildClassification rawexpr map =
match rawexpr with
| ClassFlow(x,y) -> Map.add x y map
| ClassDelim(x,y) -> buildClassification x (buildClassification y map)
| _ -> map
// Function to automatically classify all variables in programs
let rec autoClassify setVar (lvlx, lvly) =
Set.fold (
fun map var -> Map.add var lvlx map
) Map.empty setVar
// Function that takes two sets and builds a flow between sets (=>)
let doubleFlow setx sety =
Set.fold (
fun set x ->
let setu = Set.fold(
fun setv y ->
Set.add (x,y) setv
) Set.empty sety
Set.union set setu
) Set.empty setx
//doubleFlow (Set.ofList [1;2;3]) (Set.ofList [4;5;6]);; // For testing the function
// Security semantic functions
let rec secC command setX =
match command with
| Skip -> Set.empty
| Assign(x,a) -> doubleFlow (Set.union (fvArith(a)) setX) (Set.singleton x)
| ArrayAssign(A, a1, a2) -> doubleFlow (Set.union (Set.union (fvArith(a1)) (fvArith(a2)) ) setX) (Set.singleton A)
| Do(_,gc) ->
let (w, d) = secGC gc (Bool(false), setX)
w
| If(gc) ->
let (w,d) = secGC gc (Bool(false), setX)
w
| Order(c1,c2) ->
Set.union (secC c1 setX) (secC c2 setX)
and secGC guardcom (d, setX) =
match guardcom with
| IfThen(b,com) ->
let w = secC com (Set.union (Set.union (fvBool(b)) setX) (fvBool(d)) )
(w, ShortCircuitOr(b,d) )
| FatBar(gc1,gc2) ->
let (w1,d1) = secGC gc1 (d,setX)
let (w2,d2) = secGC gc2 (d1,setX)
(Set.union w1 w2, d2)
// Predefined lattices of two levels
let confidentiality = Set.singleton ("public", "private")
let integrity = Set.singleton ("trusted", "dubious")
let classical = Set.singleton ("low", "high")
let isolation = Set.ofList [("clean","Facebook");("clean","Google");("clean","Microsoft")]
// Permited (allowed) flows computed based on lattice,
//classification and actual flows in program
let rec allowFlows (lattice, classif) actual =
Set.fold (
fun set (x, y) ->
let levelx = Map.find x classif
let levely = Map.find y classif
match Set.contains (levelx, levely) lattice with
| true -> Set.add (x,y) set
| false when levelx=levely -> Set.add (x,y) set
| false -> set
) Set.empty actual
//let tryAllow = allowFlows (confidentiality, Map.ofList [("x","public");("y","private")]) (Set.ofList [("x","y");("y","x")]);;
// Check if flows in program are a subset of the allowed flows
let rec secureProgram program allowedFlows actualFlows =
Set.difference actualFlows allowedFlows
//secureProgram (Assign(StrA("x"), StrA("y"))) tryAllow;;
// Pretty printer for the set of flows
let printSetFlows set =
Set.fold (fun str (x,y) -> str+x+"->"+y+"; ") "" set
// Pretty printer for the security classification
let printClassification map =
Map.fold (fun str var lvl -> str+var+" ∈ "+lvl+"; ") "" map
// Pretty printer for the security lattice
let printLattice lattice =
Set.fold (fun str (x,y) -> str+x+" ⊑ "+y+"; ") "" lattice
// Eliminate reflexive level flows in lattice
let elimReflexive lattice =
Set.fold (
fun set (lvlx, lvly) ->
match lvlx=lvly with
| true -> set
| false -> Set.add (lvlx, lvly) set
) Set.empty lattice
// Eliminate symmetric level flows in lattice
let elimSymmetric lattice =
Set.fold (
fun set (lvlx, lvly) ->
match Set.exists (fun item -> item=(lvly, lvlx)) set with
| true -> set
| false -> Set.add (lvlx, lvly) set
) Set.empty lattice
// Eliminate transitive level flows in lattice
let elimTransitive lattice =
Set.fold (
fun set (lvlx, lvly) ->
let temp = Set.filter (fun (first, second) -> first=lvly) set
let bls = Set.exists (
fun (first, lvlz) -> Set.exists (fun item -> item=(lvlz, lvlx)) set
) temp
match bls with
| true -> set
| false -> Set.add (lvlx, lvly) set
) Set.empty lattice
// Partially Ordered Set checker on lattices
let checkPartOrdered lattice =
let noReflexive = elimReflexive lattice
let noSymmetric = elimSymmetric noReflexive
let noTransitive = elimTransitive noSymmetric
noReflexive = noTransitive
// Testing utilities
// let fakeLattice = Set.ofList [
// ("public","personA");
// ("public","public");
// ("personA","private");
// ("private","public");
// ("public","private");]
// let goodLattice = Set.ofList [
// ("public","person");
// ("public","company");
// ("company","private");
// ("person","private");]