How does the CLP model checker work?
Protocol rules are specified using MSR with constraints.
Constraints are used for freshness, for distinguishing honest principals
from
Trudy (id=0).
Goals are specified via "minimal violations", i.e., their denotations
are the "upward closure"
of the set of predicate that specify the violations.
The CLP program tries to "saturate" the set of all possible "preconditions"
with respect to the given
the given violations.
If a fixpoint is reached we can serach for "potential initial states".
This gives us a way to "infer" preconditions on possible attacks.
If no "real" initial state is found (e.g. states in which Trudy has no
initial knowledge
about keys and nonces), then the violations cannot be "reached".
This proves the protocol free from "attacks" wrt the property take into
consideration (under the assumption taken in the model)
for any number of principals, nonces, and parallel sessions.
More details:
Protocol specification
The protocol is specified using multiset rewriting rule annotated
with constraints
E.g. first NS rule:
fresh(X) ---> fresh(Y) | step1(A,<Na,B>) | enc(B,<Na,A>)
: A>0,B>0,Y>NA,NA>X
where fresh (together with the constraints) is used to ensure freshness
of names
In CLP the rules are written using the predicate "rule",
e.g.,
rule([fresh(X)], [fresh(Y),step1(A,tuple(NA,B)),enc(B,tuple(NA,A))],
{A>0,B>0,Y>NA,NA>X}, first).
Initial states
You can leave the definition of the initial states "open".
E.g. I only require that there cannot be agents in an intermediate steps
or
pending messages in an initial state.
I use the predicate init(K,L) for this.
I use it only after the fixpoint is reached.
Properties/Goals
You can express a set of "mininal violations" to a given "safety property"
as "constrained configurations"
E.g. "Bob believes he exchanged a nonce with Alice, Trudy got the nonce"
step4(B,tuple(NA,_,A)) | mem(NA) : B>0,A>0
They represent "all multisets (configurations) that include an instance
of the minimal
violation" (upward-closure of the instances, i.e., if I add other informations/agents
the resulting configuration still represents a "violation".
In CLP unsfae states are written using the predicate "unsafe" (that
takes a list as
parameter)
E.g.
unsafe([
unsafe([step3(A,tuple(NA,_,B)),mem(NA)], {A>0,B>0}),
unsafe([step3(A,tuple(_,NB,B)),mem(NB)], {A>0,B>0}),
unsafe([step4(B,tuple(NA,_,A)),mem(NA)], {A>0,B>0}),
unsafe([step4(B,tuple(_,NB,A)),mem(NB)], {A>0,B>0})
]).
denote the "union" of each set of violations denoted by every constrained
configurations
expressed as "unsafe(Multiset,Constraint)
Pre-image
Preconditions are computed "symbolically" via a "pre-image"
operator
that combines "unification" and "constraint solving"
Fixpoint termination test
Everything works modulo "constraint entailment" and "multiset subsumbption"
E.g. fresh(X) | step1(A,<Na,B>) : B>=0,Na<X
"subsumes"
fresh(X) | step1(A,<Na,B>) | step2(B,<Na,Nb,A>)
: B>0,Nb<Na,Na<X
This allows us to reason symbolically about an "unbounded number of
parallel sessions"
Running the analysis
Download the CLP source code "secmsr_pl" and the code of the examples.
Save them using ".pl" extension.
Call sicstus prolog.
Load secmsr (if you saved it as "secmsr_pl")
:-[secmsr].
Load the example (if you saved it as "ns.pl")
:-[ns].
Start the fixpoint computation using predicate "go".
:-go.
If it terminates you can inspect the resulting fixpoint using:
:- ls.
(list of all constrained configurations, each one of them has a order
number)
E.g.
f(5, [fresh(A),step1(pk(1),tuple(nonce(1),pk(2)))], {A<2.0}, 16,
14, intruderreceiveamsg_1).
must be read as:
At the 5th fixpoint iteration the constrained configuration
number 16
defined as fresh(A) | step1(pk(1) | tuple(nonce(1),pk(2)))
: A<2.0
has been obtained as symbolic precondition of that numbered
14 via the rule called
"intruderreceiveamsg_1"
:- trace(K,L).
(search for error traces, using the spec of initial states given in the
example code)
Authentication
The CLP prototype can also be used for authentication properties
(as explained in the
technical report).
During the analysis the model checker builds a symbolic backward reachability
graph
that can be studied after termination of the exploration.
Suppose that the invocation of the goal
:-go.
terminates.
By using the command
:-le.
It is posible to see the set of edges of the symbolic backward reachability
graph.
The Sicstus graph library can be used then to visit the resulting graph.
For instance,
:-buildgraph(G).
Builds show the adjacent matrix G$ associate to the graph.
:-allpaths(I).
Shows all acyclic paths starting from node I.
:-selpaths(I,K).
Shows all paths starting from node I and not passing thorough a node K.
Execution Time
To measure execution time of any CLP operation you can use the predicate
ptime
For instance,
:-ptime(go).
will print out information about CPU time needed to reach a fixpoint.