-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCSC8204_PartC_Tokeneer_Model.dfy
More file actions
184 lines (158 loc) · 5.38 KB
/
CSC8204_PartC_Tokeneer_Model.dfy
File metadata and controls
184 lines (158 loc) · 5.38 KB
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
CSC8204 Part C
Extended Dafny model for Tokeneer tokens & certificates
*/
// basic types
type optional<T> = ts: set<T> | |ts| <= 1
type TIME = nat
// Example enumerated types (CLEARANCE_CLASS and PRIVILEGE are used by the exercises).
// If your original file already defines these, keep the original definitions and remove duplicates.
// Here they are included to make this file self-contained.
datatype CLEARANCE_CLASS = unmarked | unclassified | restricted | confidential | secret | topsecret
datatype PRIVILEGE = none | normalUser | guard | auditManager | securityOfficer
// ------------------------
// Trait and certificate types
// ------------------------
trait Certificate {
var certID: nat
var tokenID: nat
var validFrom: TIME
var validTo: TIME
predicate IsCurrent(now: TIME) reads this
{ validFrom <= now && now <= validTo }
}
// Concrete certificate classes (simplified)
class IDCert extends Certificate {
constructor(id: nat, tok: nat, from: TIME, to: TIME)
ensures certID == id && tokenID == tok && validFrom == from && validTo == to
{
certID := id;
tokenID := tok;
validFrom := from;
validTo := to;
}
}
class PrivilegeCert extends Certificate {
var idCertID: nat
constructor(id: nat, tok: nat, idc: nat, from: TIME, to: TIME)
ensures certID == id && tokenID == tok && idCertID == idc && validFrom == from && validTo == to
{
certID := id;
tokenID := tok;
idCertID := idc;
validFrom := from;
validTo := to;
}
}
class IACert extends Certificate {
var idCertID: nat
constructor(id: nat, tok: nat, idc: nat, from: TIME, to: TIME)
ensures certID == id && tokenID == tok && idCertID == idc && validFrom == from && validTo == to
{
certID := id;
tokenID := tok;
idCertID := idc;
validFrom := from;
validTo := to;
}
}
class AuthorizationCert extends Certificate {
var idCertID: nat
constructor(id: nat, tok: nat, idc: nat, from: TIME, to: TIME)
ensures certID == id && tokenID == tok && idCertID == idc && validFrom == from && validTo == to
{
certID := id;
tokenID := tok;
idCertID := idc;
validFrom := from;
validTo := to;
}
}
// ------------------------
// 1) Clearance class and minClearance
// ------------------------
// Helper function to get numeric level of a clearance class
function clearanceLevel(c: CLEARANCE_CLASS): nat
{
match c
case unmarked => 0
case unclassified => 1
case restricted => 2
case confidential => 3
case secret => 4
case topsecret => 5
}
class Clearance {
var clearance: CLEARANCE_CLASS
constructor ()
ensures clearance == CLEARANCE_CLASS.unmarked
{
clearance := CLEARANCE_CLASS.unmarked;
}
// ghost function that returns the Clearance object with the lower (i.e. earlier) clearance
static function minClearance(c1: Clearance, c2: Clearance): Clearance
reads c1, c2
{
if clearanceLevel(c1.clearance) < clearanceLevel(c2.clearance) then c1 else c2
}
}
// ------------------------
// 2) Admin Privilege: ADMINOP & availableOps function
// ------------------------
// 2a) New enumerated datatype representing admin operations
datatype ADMINOP = overrideLock | archiveLog | updateData | shutdownOp
// 2b) Function that returns the set of ADMINOPs available to a given PRIVILEGE
function availableOps(p: PRIVILEGE): set<ADMINOP>
{
if p == PRIVILEGE.guard then {ADMINOP.overrideLock}
else if p == PRIVILEGE.auditManager then {ADMINOP.archiveLog}
else if p == PRIVILEGE.securityOfficer then {ADMINOP.updateData, ADMINOP.shutdownOp}
else {}
}
// ------------------------
// 3) Token class with predicates
// ------------------------
class Token {
var tokenID: nat
var idCert: IDCert
var privCert: PrivilegeCert
var iaCert: IACert
var authCert: optional<AuthorizationCert> // optional authorization certificate (0 or 1)
constructor(tid: nat, idc: IDCert, pc: PrivilegeCert, iac: IACert, ac: optional<AuthorizationCert>)
ensures tokenID == tid && idCert == idc && privCert == pc && iaCert == iac && authCert == ac
{
tokenID := tid;
idCert := idc;
privCert := pc;
iaCert := iac;
authCert := ac;
}
// Predicate: ValidToken
// A Valid Token has Privilege and I&A certificates correctly cross-referencing the ID Certificate and TokenID.
predicate ValidToken() reads this, idCert, privCert, iaCert
{
// Ensure that privilege cert references this token and the id certificate
privCert.tokenID == tokenID &&
privCert.idCertID == idCert.certID &&
// Ensure that I&A cert references this token and the id certificate
iaCert.tokenID == tokenID &&
iaCert.idCertID == idCert.certID
}
// Predicate: TokenWithValidAuth
// Must have an Authorization certificate, and it must correctly cross-reference the token ID and ID certificate ID.
predicate TokenWithValidAuth() reads this, idCert, authCert
{
// authCert is an optional set with 0 or 1 elements. We require there exists an ac in authCert
// such that it cross-references token and id certificate.
exists ac :: ac in authCert && ac.tokenID == tokenID && ac.idCertID == idCert.certID
}
// Predicate: CurrentToken(now)
// A Current Token is a Valid Token where all the certificates (id, privilege, I&A) are current at time now.
predicate CurrentToken(now: TIME) reads this, idCert, privCert, iaCert
{
ValidToken() &&
idCert.IsCurrent(now) &&
privCert.IsCurrent(now) &&
iaCert.IsCurrent(now)
}
}