-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkey-hierarchy.als
executable file
·122 lines (104 loc) · 3.75 KB
/
key-hierarchy.als
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
abstract sig Key {
// Keys can encrypt each other
encrypts: set Key,
// Keys can be stored in places in plaintext or encrypted form
places: set (Property -> set Place)
} {
// No key encrypts itself
no (this & encrypts)
}
// Keys are stored in places
abstract sig Place { }
// Keys have properties that are associated with a place the key is at
enum Property { Encrypted, Plaintext }
// So now I'm going to add people that have access to places
abstract sig Person {
// Person has access to places
access: set Place,
// They can also have access to keys
keys: set Key
} {
// If a person has access to a place then they have access to plaintext keys in that place
all k: Key | Plaintext in k.places.access => k in keys
}
// The hierarchy is acyclic
fact {
all k: Key | no (k & k.^encrypts)
}
// Every key must be owned by a person or be in some place
fact {
all k: Key | (some k.places || some p: Person | k in p.keys)
}
// If a key is encrypted in some place then it is not stored in plaintext at same place
fact {
all k: Key | no (k.places[Encrypted] & k.places[Plaintext])
}
// If a key encrypts another key then the encrypted key
// must appear encrypted somewhere
fact {
all k: Key, k': k.encrypts | some k'.places[Encrypted]
}
// If a key encrypts another key then it can not be stored in plaintext alongside it
fact {
all k: Key, k': k.encrypts | no (k.places[Plaintext] & k'.places[Property])
}
// Now some more complicated interactions between keys, people, and places. If a person
// has access to a key and that key encrypts another key that is placed somewhere
// the person has access to then that person also has access to that key
fact {
all p: Person, k: p.keys, k': k.encrypts {
some k'.places[Property] & p.access => k' in p.keys
}
}
// Now let's spell out some concrete implementations
// These are some places we will be storing keys
one sig Git, Lastpass, Production extends Place { }
// These are some people that will have access to keys and places
one sig InfraPerson, DevPerson extends Person { }
// Now let's specify some keys and their relationships
one sig DevKey, InfraKey,
InfraKeyPassword, DevKeyPassword,
LastpassPassword extends Key { }
// Facts about InfraPerson
fact {
// Infra person has all the infra keys and passwords
(InfraKey + InfraKeyPassword + LastpassPassword) in InfraPerson.keys
// InfraPerson can access everything
Place = InfraPerson.access
}
// Facts about DevPerson
fact {
// Dev person can access the dev key password
DevKeyPassword in DevPerson.keys
// They can access Git and Production
(Git + Production) = DevPerson.access
}
// Which key encrypts which other key
fact {
// The infra key password encrypts infra key
InfraKey = InfraKeyPassword.encrypts
// Lastpass encrypts infra key password and infra key
(InfraKeyPassword + InfraKey) = LastpassPassword.encrypts
// Dev key password encrypts dev key
DevKey = DevKeyPassword.encrypts
// Infra key encrypts dev key password
DevKeyPassword = InfraKey.encrypts
}
// Now we specify where each key is stored
fact {
// Infra keys are stored in lastpass
(Encrypted -> Lastpass) = InfraKeyPassword.places
(Encrypted -> Lastpass) = InfraKey.places
// Dev keys are stored in git and one of the keys is stored in production in plaintext
(Encrypted -> Git) = DevKeyPassword.places
(Encrypted -> Git + Plaintext -> Production) = DevKey.places
}
// Now we have to specify a few more facts about the keys to rule out extraneous models
fact {
// Dev key does not encrypt any other keys
no DevKey.encrypts
// Dev person does not have access to infra keys
no (InfraKey + InfraKeyPassword + LastpassPassword) & DevPerson.keys
// Lastpass password is not stored anywhere and is just owned by the infra person
no LastpassPassword.places
}