- Moved everything about.

This commit is contained in:
ccremers 2004-04-23 10:58:43 +00:00
parent ca5202dc0c
commit 0f4e6a5aba
60 changed files with 10596 additions and 0 deletions

80
src/Makefile Normal file
View File

@ -0,0 +1,80 @@
#
# Scyther Makefile
#
#
# DEBUG or optimization settings: uncomment a single line:
#
CFLAGS = -g3 -D DEBUG # default usage, for e.g. with valgrind
#CFLAGS = -g3 -D DEBUG -pg # for code profiling with gprof
#CFLAGS = -O3 -static -finline-functions -fomit-frame-pointer
#
# Compiler and linkage
#
CC = gcc
# Note that these paths must include the path to the argtable library.
CPPFLAGS = -I/scratch/ccremers/include -I/usr/local/include -Wall
LDFLAGS = -L/scratch/ccremers/lib -L/usr/local/lib
LOADLIBS = -lfl
LDLIBS = -largtable2
OPTIONS = ${CPPFLAGS} ${CFLAGS} ${LDFLAGS}
#
# Module set for the modelchecker
#
MODULES=memory.o terms.o termlists.o symbols.o knowledge.o runs.o modelchecker.o \
report.o debug.o mgu.o substitutions.o \
match_basic.o \
match_clp.o constraints.o \
output.o latex.o \
varbuf.o tracebuf.o attackminimize.o \
tac.o parser.o compiler.o
#
# Dependencies
#
MODELCHECKER = ${MODULES} main.o
all: scyther tags
${Target}.o: ${Target}.c
$(CC) $(OPTIONS) ${Target}.c -c
scanner.c: scanner.lex
flex scanner.lex
cp lex.yy.c scanner.c
tok.h: parser.c
parser.c: parser.y
bison -d -v parser.y
cp parser.tab.c parser.c
cmp -s parser.tab.h tok.h || cp parser.tab.h tok.h
tags: *.c *.h
ctags *.c *.h
modules: $(MODULES)
scyther: scanner.o $(MODELCHECKER)
$(CC) $(OPTIONS) $(MODELCHECKER) -o scyther $(LOADLIBS) $(LDLIBS)
ptestmain.o scanner.o : tok.h
#
# Cleanup
#
clean:
rm -f *.o
rm -f scyther
rm -f scanner.c
rm -f parser.c
rm -f tok.h
#
# Clean and rebuild: 'make new'
#
new:
make clean
make all

33
src/README Normal file
View File

@ -0,0 +1,33 @@
==================
# Scyther README #
==================
----------------
1. About Scyther
----------------
Scyther bla Cas andsoforth, bla Lutger, yada yada yada.
---------------
2. Requirements
---------------
Scyther compilation depends on a few external items:
- A C compiler (gcc or anything modern *nixy will do)
- The Flex and Bison scanner/compiler generation tools.
- The argtable 2 library.
The first two requirements are usually met by default by any modern *nix
variant, such as GNU/Linux.
The argtable2 library is available under the LGPL license from
http://argtable.sourceforge.net/doc/argtable2.html. Make sure the paths
in the Makefile include the path to this library.
If you want LaTeX output we need
- LaTeX
- The MSC macro package msc.sty
- preamble.tex and postamble.tex

131
src/attackminimize.c Normal file
View File

@ -0,0 +1,131 @@
#include <stdio.h>
#include <stdlib.h>
#include "runs.h"
#include "tracebuf.h"
int cUnk = 0;
int cTod = 0;
void markback(System sys, struct tracebuf *tb, int ev)
{
int run = tb->run[ev];
while (ev >= 0)
{
if (tb->run[ev] == run)
{
switch (tb->event[ev]->type)
{
case READ:
switch (tb->status[ev])
{
case S_UNK:
cUnk--;
case S_RED:
tb->status[ev] = S_TOD;
cTod++;
break;
case S_TOD:
case S_OKE:
break;
}
break;
case SEND:
case CLAIM:
if (tb->status[ev] == S_UNK)
{
cUnk--;
}
tb->status[ev] = S_OKE;
break;
}
}
ev--;
}
}
void attackMinimize(System sys, struct tracebuf *tb)
{
int i;
int j;
cUnk = 0;
cTod = 0;
for (i=0; i < tb->length; i++)
{
switch (tb->status[i])
{
case S_UNK:
cUnk++;
break;
case S_TOD:
cTod++;
break;
default:
break;
}
}
markback(sys, tb, tb->violatedclaim);
while (cUnk + cTod > 0)
{
while (cTod > 0)
{
for (i = 0; i < tb->length; i++)
// kies een i; laten we de eerste maar pakken
{
if (tb->status[i] == S_TOD)
break;
}
if (i == tb->length)
{
printf("Some step error.\n");
exit(1);
}
j = i;
while (j >= 0 && inKnowledge(tb->know[j], tb->event[i]->message))
{
// zoek waar m in de kennis komt
j--;
}
tb->status[i] = S_OKE;
cTod--;
if (j>=0)
{
markback(sys,tb,j);
}
}
while (cTod == 0 && cUnk > 0)
{
for (i = tb->length-1; i>=0; i--)
// pak laatste i
{
if (tb->status[i] == S_UNK)
break;
}
if (i < 0)
{
printf("Some i<0 error.\n");
exit(1);
}
tb->status[i] = S_RED;
cUnk--;
tb->reallength--;
j = tracebufRebuildKnow(tb);
if (j>-1)
{
tb->reallength++;
markback(sys,tb,i);
if (j < tb->length)
{
tb->link[j] = (tb->link[j] > i ? tb->link[j] : i);
}
}
}
}
}

1
src/attackminimize.h Normal file
View File

@ -0,0 +1 @@
void attackMinimize(System sys, struct tracebuf *tb);

6
src/cetest-cm.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
#
# Test conform ce stuff, but our version
#
./scyther -r5 $* <spdl/bkepk.spdl
./scyther -r6 $* <spdl/bkepk.spdl | tail -n 1

10
src/cetest.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
#
# Test conform ce stuff.
#
./scyther -r6 $* <spdl/bkepk-ce.spdl
./scyther -r7 $* <spdl/bkepk-ce.spdl | tail -n 1
./scyther -r8 $* <spdl/bkepk-ce.spdl | tail -n 1
./scyther -r7 $* <spdl/bkepk-ce2.spdl | tail -n 1
./scyther -r8 $* <spdl/bkepk-ce2.spdl | tail -n 1
./scyther -r9 $* <spdl/bkepk-ce2.spdl | tail -n 1

732
src/compiler.c Normal file
View File

@ -0,0 +1,732 @@
#include <stdlib.h>
#include <stdio.h>
#include "tac.h"
#include "terms.h"
#include "termlists.h"
#include "runs.h"
#include "knowledge.h"
#include "symbols.h"
#include "substitutions.h"
#include "compiler.h"
/*
Simple sys pointer as a global. Yields cleaner code although it's against programming standards.
It is declared as static to hide it from the outside world, and to indicate its status.
Other modules will just see a nicely implemented sys parameter of compile, so we can always change
it later if somebody complains. Which they won't.
*/
static System sys;
/*
Forward declarations.
*/
void tacProcess (Tac tc);
void levelInit (void);
void levelDone (void);
Term symbolDeclare (Symbol s, int isVar);
void levelTacDeclaration (Tac tc, int isVar);
Term levelFind (Symbol s, int i);
Term symbolFind (Symbol s);
Term tacTerm (Tac tc);
Termlist tacTermlist (Tac tc);
#define levelDeclareVar(s) levelTacDeclaration(s,1)
#define levelDeclareConst(s) levelTacDeclaration(s,0)
#define levelVar(s) symbolDeclare(s,1)
#define levelConst(s) symbolDeclare(s,0)
/* externally used:
* TERM_Function in termlists.c for inversekeys
* TERM_Type in runs.c for type determination.
*/
Term TERM_Agent;
Term TERM_Function;
Term TERM_Hidden;
Term TERM_Type;
Term TERM_Nonce;
Term TERM_Agent;
Term TERM_Claim;
Term CLAIM_Secret;
Term CLAIM_Nisynch;
/*
* Global stuff
*/
#define MAXLEVELS 3
static Termlist leveltl[MAXLEVELS];
static int level;
static int maxruns;
static Protocol thisProtocol;
static Role thisRole;
/* ------------------------------------------------------------------- */
/*
Compile the tac into the system
*/
void
compile (System mysys, Tac tc, int maxrunsset)
{
int i;
/* Init globals */
maxruns = maxrunsset;
/* transfer to global static variable */
sys = mysys;
/* init levels */
for (i = 0; i < MAXLEVELS; i++)
leveltl[i] = NULL;
level = -1;
levelInit ();
/* Init system constants */
#define langhide(x,y) x = levelConst(symbolSysConst(" _" y "_ "))
#define langtype(x,y) x->stype = termlistAdd(x->stype,y);
#define langcons(x,y,z) x = levelConst(symbolSysConst(y)); langtype(x,z)
langhide (TERM_Type, "Type");
langhide (TERM_Hidden, "Hidden");
langhide (TERM_Claim, "Claim");
langcons (TERM_Agent, "Agent", TERM_Type);
langcons (TERM_Function, "Function", TERM_Type);
langcons (TERM_Nonce, "Nonce", TERM_Type);
langcons (CLAIM_Secret, "Secret", TERM_Claim);
langcons (CLAIM_Nisynch, "Nisynch", TERM_Claim);
/* process the tac */
tacProcess (tc);
/* cleanup */
levelDone ();
}
void
errorTac (int lineno)
{
printf (" on line %i.\n", lineno);
exit (1);
}
void
levelInit (void)
{
level++;
if (level >= MAXLEVELS)
{
printf ("ERROR: level is increased too much\n");
exit (1);
}
leveltl[level] = NULL;
}
void
levelDone (void)
{
if (level < 0)
{
printf ("ERROR: level is increased too much\n");
exit (1);
}
leveltl[level] = NULL;
level--;
}
Term
levelDeclare (Symbol s, int isVar, int level)
{
Term t;
t = levelFind (s, level);
if (t == NULL)
{
/* new! */
if (isVar)
{
t = makeTermType (VARIABLE, s, -(level + 1));
sys->variables = termlistAdd (sys->variables, t);
}
else
{
t = makeTermType (GLOBAL, s, -(level + 1));
}
leveltl[level] = termlistAdd (leveltl[level], t);
/* add to relevant list */
switch (level)
{
case 0:
sys->locals = termlistAdd (sys->locals, t);
break;
case 1:
thisProtocol->locals = termlistAdd (thisProtocol->locals, t);
break;
case 2:
thisRole->locals = termlistAdd (thisRole->locals, t);
break;
}
}
return t;
}
Term
symbolDeclare (Symbol s, int isVar)
{
return levelDeclare (s, isVar, level);
}
Term
levelFind (Symbol s, int level)
{
Termlist tl;
tl = leveltl[level];
while (tl != NULL)
{
if (isTermLeaf (tl->term))
{
if (tl->term->symb == s)
{
return tl->term;
}
}
tl = tl->next;
}
return NULL;
}
Term
symbolFind (Symbol s)
{
int i;
Term t;
i = level;
while (i >= 0)
{
t = levelFind (s, i);
if (t != NULL)
return t;
i--;
}
return NULL;
}
void
defineUsertype (Tac tcdu)
{
Tac tc;
Term t;
Term tfind;
tc = tcdu->tac1;
if (tc == NULL)
{
printf ("ERROR: empty usertype declaration.\n");
errorTac (tcdu->lineno);
}
while (tc != NULL && tc->op == TAC_STRING)
{
/* check whether this term is already declared in the same way
* (i.e. as a type) */
tfind = levelFind (tc->sym1, 0);
if (tfind == NULL)
{
/* this is what we expected: this type is not declared yet */
t = levelDeclare (tc->sym1, 0, 0);
t->stype = termlistAdd (NULL, TERM_Type);
}
else
{
/* oi!, there's already one. Let's hope is is a type too. */
if (inTermlist (tfind->stype, TERM_Type))
{
/* phew. warn anyway */
printf ("WARNING: double declaration of usertype ");
termPrint (tfind);
printf ("\n");
}
else
{
/* that's not right! */
printf ("ERROR: conflicting definitions for ");
termPrint (tfind);
printf (" in usertype definition ");
errorTac (tc->lineno);
}
}
tc = tc->next;
}
}
void
levelTacDeclaration (Tac tc, int isVar)
{
Tac tscan;
Termlist typetl = NULL;
Term t;
tscan = tc->tac2;
if (!isVar && tscan->next != NULL)
{
printf ("ERROR: Multiple types not allowed for constants ");
errorTac (tscan->lineno);
}
while (tscan != NULL && tscan->op == TAC_STRING)
{
/* apparently there is type info, termlist? */
t = levelFind (tscan->sym1, 0);
if (t == NULL)
{
/* not declared, that is unacceptable. */
printf ("ERROR: type ");
symbolPrint (tscan->sym1);
printf (" was not declared ");
errorTac (tscan->lineno);
}
else
{
if (!inTermlist (t->stype, TERM_Type))
{
printf ("ERROR: non-type constant in type declaration ");
errorTac (tscan->lineno);
}
}
typetl = termlistAdd (typetl, t);
tscan = tscan->next;
}
/* parse all constants and vars */
tscan = tc->tac1;
while (tscan != NULL)
{
t = symbolDeclare (tscan->sym1, isVar);
t->stype = typetl;
tscan = tscan->next;
}
}
void
commEvent (int event, Tac tc)
{
/* Add an event to the roledef, send or read */
Term fromrole = NULL;
Term torole = NULL;
Term msg = NULL;
Term label = NULL;
Term claim = NULL;
Term claimbig = NULL;
int n = 0;
Tac trip;
/* Construct label, if any */
if (tc->sym1 == NULL)
{
label = NULL;
}
else
{
label = levelFind (tc->sym1, level - 1);
if (label == NULL)
{
/* effectively, labels are bound to the protocol */
level--;
label = levelConst (tc->sym1);
level++;
}
}
trip = tc->tac2;
switch (event)
{
case READ:
case SEND:
/* now parse triplet info */
if (trip == NULL || trip->next == NULL || trip->next->next == NULL)
{
printf ("ERROR in %i event ", event);
errorTac (tc->lineno);
}
fromrole = tacTerm (trip);
torole = tacTerm (trip->next);
msg = tacTerm (tacTuple ((trip->next->next)));
break;
case CLAIM:
/* now parse tuple info */
if (trip == NULL || trip->next == NULL)
{
printf ("ERROR in %i event ", event);
errorTac (tc->lineno);
}
fromrole = tacTerm (trip);
claimbig = tacTerm (tacTuple ((trip->next)));
/* check for several types */
claim = tupleProject (claimbig, 0);
torole = claim;
/* check for obvious flaws */
if (claim == NULL)
{
printf ("ERROR: invalid claim specification ");
errorTac (trip->next->lineno);
}
if (!inTermlist (claim->stype, TERM_Claim))
{
printf ("ERROR: unknown claim type ");
termPrint (claim);
errorTac (trip->next->lineno);
}
/* unfold parameters to msg */
msg = NULL;
n = tupleCount (claimbig) - 1;
if (n < 1)
{
/* no parameters */
n = 0;
}
else
{
/* n parameters */
msg = deVar (claimbig)->op2;
if (tupleCount (msg) != n)
{
printf
("ERROR: something went wrong in the claim tuple parameter unfolding ");
errorTac (trip->next->lineno);
}
}
/* handles all claim types differently */
if (claim == CLAIM_Secret)
{
if (n == 0)
{
printf
("ERROR: secrecy claim requires a list of terms to be secret ");
errorTac (trip->next->lineno);
}
break;
}
if (claim == CLAIM_Nisynch)
{
if (n != 0)
{
printf ("ERROR: nisynch claim has no parameters ");
errorTac (trip->next->lineno);
}
break;
}
/* hmm, no handler yet */
printf ("ERROR: No know handler for this claim type: ");
termPrint (claim);
printf (" ");
errorTac (trip->next->lineno);
break;
}
/* and make that event */
thisRole->roledef = roledefAdd (thisRole->roledef, event, label,
fromrole, torole, msg);
}
int
normalDeclaration (Tac tc)
{
switch (tc->op)
{
case TAC_VAR:
levelDeclareVar (tc);
if (level < 2 && tc->tac3 == NULL)
knowledgeAddTermlist (sys->know, tacTermlist (tc->tac1));
break;
case TAC_CONST:
levelDeclareConst (tc);
if (level < 2 && tc->tac3 == NULL)
knowledgeAddTermlist (sys->know, tacTermlist (tc->tac1));
break;
case TAC_SECRET:
levelDeclareConst (tc);
break;
case TAC_COMPROMISED:
knowledgeAddTermlist (sys->know, tacTermlist (tc->tac1));
break;
case TAC_INVERSEKEYS:
knowledgeAddInverse (sys->know, tacTerm (tc->tac1), tacTerm (tc->tac2));
break;
default:
/* abort with false */
return 0;
}
return 1;
}
void
roleCompile (Term nameterm, Tac tc)
{
Role r;
/* make new (empty) current protocol with name */
r = roleCreate (nameterm);
thisRole = r;
/* add protocol to list */
r->next = thisProtocol->roles;
thisProtocol->roles = r;
/* parse the content of the role */
levelInit ();
while (tc != NULL)
{
switch (tc->op)
{
case TAC_READ:
commEvent (READ, tc);
break;
case TAC_SEND:
commEvent (SEND, tc);
break;
case TAC_CLAIM:
commEvent (CLAIM, tc);
break;
default:
if (!normalDeclaration (tc))
{
printf ("ERROR: illegal command %i in role ", tc->op);
termPrint (thisRole->nameterm);
printf (" ");
errorTac (tc->lineno);
}
break;
}
tc = tc->next;
}
levelDone ();
}
void
runInstanceCreate (Tac tc)
{
/* create an instance of an existing role
* tac1 is the dot-separated reference to the role.
* tac2 is the list of parameters to be filled in.
*/
Protocol p;
Role r;
Symbol psym, rsym;
Termlist instParams;
/* check whether we can still do it */
if (sys->maxruns >= maxruns)
return;
/* first, locate the protocol */
psym = tc->tac1->sym1;
p = sys->protocols;
while (p != NULL && p->nameterm->symb != psym)
p = p->next;
if (p == NULL)
{
printf ("Trying to create a run of a non-declared protocol ");
symbolPrint (psym);
printf (" ");
errorTac (tc->lineno);
}
/* locate the role */
rsym = tc->tac1->sym2;
r = p->roles;
while (r != NULL && r->nameterm->symb != rsym)
r = r->next;
if (r == NULL)
{
printf ("Protocol ");
symbolPrint (psym);
printf (" has no role called ");
symbolPrint (rsym);
printf (" ");
errorTac (tc->lineno);
}
/* we now know what we are instancing, equal numbers? */
instParams = tacTermlist (tc->tac2);
if (termlistLength (instParams) != termlistLength (p->rolenames))
{
printf
("Run instance has different number of parameters than protocol ");
termPrint (p->nameterm);
printf (" ");
errorTac (tc->lineno);
}
/* equal numbers, so it seems to be safe */
roleInstance (sys, p, r, instParams);
/* after creation analysis */
/* AC1: untrusted agents */
/* first: determine whether the run is untrusted,
* by checking whether one of the untrusted agents occurs
* in the run instance */
if (untrustedAgent (sys, instParams))
{
/* nothing yet */
/* claims handle this themselves */
/* some reduction might be possible, by cutting of the last few actions
* of such an untrusted run */
/* but most of it might be handled dynamically */
}
/* AC2: originator assumption for CLP ? */
/* TODO */
}
void
protocolCompile (Symbol prots, Tac tc, Tac tcroles)
{
Protocol pr;
Term t;
if (levelFind (prots, level) != NULL)
{
printf ("ERROR: Double declaration of protocol ");
symbolPrint (prots);
printf (" ");
errorTac (tc->lineno);
}
/* make new (empty) current protocol with name */
pr = protocolCreate (levelConst (prots));
thisProtocol = pr;
/* add protocol to list */
pr->next = sys->protocols;
sys->protocols = pr;
levelInit ();
/* add the role names */
pr->rolenames = NULL;
while (tcroles != NULL)
{
pr->rolenames =
termlistAppend (pr->rolenames, levelConst (tcroles->sym1));
tcroles = tcroles->next;
}
/* parse the content of the protocol */
while (tc != NULL)
{
switch (tc->op)
{
case TAC_UNTRUSTED:
sys->untrusted =
termlistConcat (sys->untrusted, tacTermlist (tc->tac1));
break;
case TAC_ROLE:
t = levelFind (tc->sym1, level);
if (t != NULL)
{
roleCompile (t, tc->tac2);
}
else
{
printf ("ERROR: undeclared role ");
symbolPrint (tc->sym1);
printf (" in protocol ");
termPrint (pr->nameterm);
errorTac (tc->sym1->lineno);
}
break;
default:
if (!normalDeclaration (tc))
{
printf ("ERROR: illegal command %i in protocol ", tc->op);
termPrint (thisProtocol->nameterm);
errorTac (tc->lineno);
}
break;
}
tc = tc->next;
}
levelDone ();
}
void
tacProcess (Tac tc)
{
while (tc != NULL)
{
switch (tc->op)
{
case TAC_PROTOCOL:
protocolCompile (tc->sym1, tc->tac2, tc->tac3);
break;
case TAC_UNTRUSTED:
sys->untrusted =
termlistConcat (sys->untrusted, tacTermlist (tc->tac1));
break;
case TAC_RUN:
runInstanceCreate (tc);
break;
case TAC_USERTYPE:
defineUsertype (tc);
break;
default:
if (!normalDeclaration (tc))
{
printf ("ERROR: illegal command %i at the global level.\n",
tc->op);
errorTac (tc->lineno);
}
break;
}
tc = tc->next;
}
}
Term
tacTerm (Tac tc)
{
switch (tc->op)
{
case TAC_ENCRYPT:
return makeTermEncrypt (tacTerm (tc->tac1), tacTerm (tc->tac2));
case TAC_TUPLE:
return makeTermTuple (tacTerm (tc->tac1), tacTerm (tc->tac2));
case TAC_STRING:
{
Term t = symbolFind (tc->sym1);
if (t == NULL)
{
printf ("Undeclared symbol ");
symbolPrint (tc->sym1);
errorTac (tc->lineno);
}
return t;
}
default:
return NULL;
}
}
Termlist
tacTermlist (Tac tc)
{
Termlist tl = NULL;
while (tc != NULL)
{
tl = termlistAppend (tl, tacTerm (tc));
tc = tc->next;
}
return tl;
}

6
src/compiler.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef COMPILER
#define COMPILER
void compile (System sys, Tac tc, int maxruns);
#endif

336
src/constraints.c Normal file
View File

@ -0,0 +1,336 @@
#include <stdio.h>
#include "memory.h"
#include "constraints.h"
#include "debug.h"
#include "runs.h"
/* constraints currently are shallow copies */
Constraint
makeConstraint (Term term, Knowledge know)
{
/* maybe knowDup can just be a link, but then it needs to be moved from destroy as well */
Constraint co = memAlloc (sizeof (struct constraint));
co->term = term;
//co->know = knowledgeDuplicate(know);
co->know = know;
return co;
}
Constraint
constraintDuplicate (Constraint co)
{
return makeConstraint (co->term, co->know);
}
void
constraintDestroy (Constraint cons)
{
//knowledgeDelete(cons->know);
if (cons != NULL)
memFree (cons, sizeof (struct constraint));
}
/* constraints are typically added at the end, to maintain the order in which they were added */
Constraintlist
constraintlistAdd (Constraintlist cl, Constraint co)
{
Constraintlist clnew = memAlloc (sizeof (struct constraintlist));
clnew->constraint = co;
clnew->next = NULL;
if (cl == NULL)
{
clnew->prev = NULL;
return clnew;
}
else
{
Constraintlist scan;
scan = cl;
while (scan->next != NULL)
scan = scan->next;
scan->next = clnew;
clnew->prev = scan;
return cl;
}
}
Constraintlist
constraintlistConcat (Constraintlist cl1, Constraintlist cl2)
{
Constraintlist scan;
if (cl1 == NULL)
return cl2;
scan = cl1;
while (scan->next != NULL)
scan = scan->next;
scan->next = cl2;
return cl1;
}
Constraintlist
constraintlistRewind (Constraintlist cl)
{
if (cl == NULL)
return NULL;
while (cl->prev != NULL)
cl = cl->prev;
return cl;
}
Constraintlist
constraintlistInsert (Constraintlist cl, Term term, Knowledge know)
{
Constraintlist clnew = memAlloc (sizeof (struct constraintlist));
clnew->constraint = makeConstraint (term, know);
if (cl != NULL)
{
if (cl->next != NULL)
{
clnew->next = cl->next;
cl->next->prev = cl;
}
else
{
clnew->next = NULL;
}
clnew->prev = cl;
cl->next = clnew;
return constraintlistRewind (cl);
}
else
{
clnew->next = NULL;
clnew->prev = NULL;
return clnew;
}
}
/* unlink a single constraint */
Constraintlist
constraintlistUnlink (Constraintlist cl)
{
Constraintlist clnext, clprev;
if (cl == NULL)
return NULL;
clprev = cl->prev;
clnext = cl->next;
if (clnext != NULL)
{
clnext->prev = clprev;
cl->next = NULL;
}
if (clprev != NULL)
{
clprev->next = clnext;
cl->prev = NULL;
return constraintlistRewind (clprev);
}
else
{
return clnext;
}
}
/* remove a single constraint */
Constraintlist
constraintlistRemove (Constraintlist cl)
{
Constraintlist clnew;
clnew = constraintlistUnlink (cl);
memFree (cl, sizeof (struct constraintlist));
return clnew;
}
/* remove all constraints from this point onwards */
void
constraintlistDelete (Constraintlist cl)
{
Constraintlist cldel;
/* no empty cl */
if (cl == NULL)
return;
/* cut off previous */
if (cl->prev != NULL)
{
/* TODO maybe this should cause a warning? */
printf ("WARNING: clDelete with non-empty prev\n");
cl->prev->next = NULL;
}
while (cl != NULL)
{
cldel = cl;
cl = cl->next;
memFree (cldel, sizeof (struct constraintlist));
}
return;
}
void
constraintlistDestroy (Constraintlist cl)
{
Constraintlist cldel;
/* no empty cl */
if (cl == NULL)
return;
/* cut off previous */
if (cl->prev != NULL)
{
/* TODO maybe this should cause a warning? */
printf ("WARNING: clDestroy with non-empty prev\n");
cl->prev = NULL;
}
while (cl != NULL)
{
cldel = cl;
cl = cl->next;
constraintDestroy (cldel->constraint);
memFree (cldel, sizeof (struct constraintlist));
}
}
Constraintlist
constraintlistDuplicate (Constraintlist oldcl)
{
Constraintlist newcl = NULL;
while (oldcl != NULL)
{
newcl =
constraintlistAdd (newcl, constraintDuplicate (oldcl->constraint));
oldcl = oldcl->next;
}
return newcl;
}
Constraintlist
constraintlistShallow (Constraintlist oldcl)
{
Constraintlist newcl = NULL;
while (oldcl != NULL)
{
newcl = constraintlistAdd (newcl, oldcl->constraint);
oldcl = oldcl->next;
}
return newcl;
}
/* ----------------------------------------------------------
Print stuff
---------------------------------------------------------- */
void
constraintPrint (Constraint co)
{
indent ();
printf ("Constraint ");
if (co == NULL)
{
printf ("[empty]\n");
return;
}
termPrint (co->term);
printf (" :\n");
knowledgePrint (co->know);
}
void
constraintlistPrint (Constraintlist cl)
{
if (cl == NULL)
{
indent ();
printf ("[empty constraintlist]\n");
return;
}
while (cl != NULL)
{
constraintPrint (cl->constraint);
cl = cl->next;
}
}
/* ----------------------------------------------------------
Now some real logic for the constraints
---------------------------------------------------------- */
/* eliminate all standalone variables */
void
msElim (Constraint co)
{
Termlist tl;
/* simple variables can only exist in basic */
if (co->know == NULL)
{
#ifdef DEBUG
debug (5, "Exiting because co->know is empty.");
#endif
}
else
{
tl = co->know->basic;
while (tl != NULL)
{
if (isTermVariable (tl->term))
{
tl = termlistDelTerm (tl);
co->know->basic = tl;
}
else
tl = tl->next;
}
}
}
/* find the first constraint such that m is not a variable */
/* also, apply standalone elimination to it */
Constraintlist
firstNonVariable (Constraintlist cl)
{
while (cl != NULL && isTermVariable (cl->constraint->term))
{
cl = cl->next;
}
if (cl != NULL)
{
msElim (cl->constraint);
cl->constraint->term = deVar (cl->constraint->term);
return cl;
}
else
{
return NULL;
}
}

42
src/constraints.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef CONSTRAINTS
#define CONSTRAINTS
#include "terms.h"
#include "knowledge.h"
struct constraint
{
Term term;
Knowledge know;
};
typedef struct constraint *Constraint;
struct constraintlist
{
Constraint constraint;
struct constraintlist *next;
struct constraintlist *prev;
};
typedef struct constraintlist *Constraintlist;
Constraint makeConstraint (Term term, Knowledge know);
Constraint constraintDuplicate (Constraint co);
void constraintDestroy (Constraint cons);
Constraintlist constraintlistAdd (Constraintlist cl, Constraint co);
Constraintlist constraintlistConcat (Constraintlist cl1, Constraintlist cl2);
Constraintlist constraintlistRewind (Constraintlist cl);
Constraintlist constraintlistInsert (Constraintlist cl, Term term,
Knowledge know);
Constraintlist constraintlistUnlink (Constraintlist cl);
Constraintlist constraintlistRemove (Constraintlist cl);
void constraintlistDestroy (Constraintlist cl);
void constraintlistDelete (Constraintlist cl);
Constraintlist constraintlistShallow (Constraintlist oldcl);
Constraintlist constraintlistDuplicate (Constraintlist oldcl);
void constraintPrint (Constraint co);
void constraintlistPrint (Constraintlist cl);
Constraintlist firstNonVariable (Constraintlist cl);
#endif

30
src/debug.c Normal file
View File

@ -0,0 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
#include "runs.h"
static int debuglevel;
void
debugSet (int level)
{
debuglevel = level;
}
int
debugCond (int level)
{
return (level <= debuglevel);
}
void
debug (int level, char *string)
{
#ifdef DEBUG
if (debugCond (level))
{
indent ();
printf ("DEBUG [%i]: %s\n", level, string);
}
#endif
}

10
src/debug.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef DEBUG_H
#define DEBUG_H
void debugSet (int level);
int debugCond (int level);
void debug (int level, char *string);
#define DEBUGL(a) debugCond(a)
#endif

7
src/debuglevels.txt Normal file
View File

@ -0,0 +1,7 @@
Conventions for debug levels; ifdef DEBUG
-D1 meta show compiled code, meta dynamic results
-D2 claims show results of claims
-D3 events show executed events
-D4 internalsHigh interesting internals (traces that were cut off)
-D5 internalsLow usually uninteresting stuff

47
src/design.txt Normal file
View File

@ -0,0 +1,47 @@
Design Issues for the Model Checker
-----------------------------------
- For secrecy, we can trigger all sends at once. For synchronisation,
this is not the case.
- Modules have to be split up sensibly.
- Although 'knowledge' and 'term matching' seem to different items,
their intertwined workings suggest that they should be implemented
in parallel.
- State generation (as in creating instances) might already allow for
a lot of static analysis.
- We should make a list of required operations. Ingmar's work can serve
as a starting point.
- For now, there will be no parser, and test cases will be input by
hand.
- Synchronisation is more difficult to test, so we focus on secrecy
first. I've got some good ideas on Synchronisation testing though
(with narrowing sets of possible partners). Synchronisation is very
hard to prune, I presume. I have to prove that though ;)
Sketch for secrecy:
SimulateStep(F,M,constraints):
if Empty(F):
return
else:
for (s in PossibleSends):
add s.message to M
if (secrecy violated):
halt
remove s from F
ReadSets = supersetTransitions(F)
for (ReadSet in ReadSets):
for (s in ReadSet):
// dit is vaag
if NonMatch goto next ReadSet
constraint = F,M,match()
SimulateStep(F \ s,M,constraints)

474
src/knowledge.c Normal file
View File

@ -0,0 +1,474 @@
#include <stdlib.h>
#include <stdio.h>
#include "termlists.h"
#include "knowledge.h"
#include "memory.h"
#include "runs.h"
#include "debug.h"
/*
* Knowledge stuff
*
* Note that a really weird thing is going on involving unpropagated substitutions.
* Idea:
*
* 1. Substitute terms by filling in ->subst.
* Now, either:
* 2a. Undo this by knowledgeUndo.
* 2b. Propagate it, modifying the knowledge beyond repair by knowledgeSubstDo. Now inKnowledge works again.
* 2c. inKnowledge/knowledgeSet if something is in the knowledge: this does not consider the substitutions!, and
* they now have some overhead.
*/
void
knowledgeInit (void)
{
return;
}
void
knowledgeDone (void)
{
}
Knowledge
makeKnowledge ()
{
return (Knowledge) memAlloc (sizeof (struct knowledge));
}
Knowledge
emptyKnowledge ()
{
Knowledge know;
know = makeKnowledge ();
know->basic = NULL;
know->encrypt = NULL;
know->inverses = NULL;
know->vars = NULL;
return know;
}
Knowledge
knowledgeDuplicate (Knowledge know)
{
Knowledge newknow;
if (know == NULL)
{
printf ("Warning! Trying to copy empty knowledge!\n");
return NULL;
}
newknow = makeKnowledge ();
newknow->basic = termlistShallow (know->basic);
newknow->encrypt = termlistShallow (know->encrypt);
newknow->vars = termlistShallow (know->vars);
newknow->inverses = know->inverses;
return newknow;
}
void
knowledgeDelete (Knowledge know)
{
if (know != NULL)
{
termlistDelete (know->basic);
termlistDelete (know->encrypt);
termlistDelete (know->vars);
memFree (know, sizeof (struct knowledge));
}
}
void
knowledgeDestroy (Knowledge know)
{
if (know != NULL)
{
termlistDestroy (know->basic);
termlistDestroy (know->encrypt);
termlistDestroy (know->vars);
// termlistDestroy(know->inverses);
memFree (know, sizeof (struct knowledge));
}
}
/*
* knowledgeAddTerm
*
* returns a boolean:
* true iff the term was actually new, and added.
*/
int
knowledgeAddTerm (Knowledge know, Term term)
{
if (know == NULL)
{
printf
("Warning: trying to add term to uninitialised (NULL) Know pointer.\n");
return 1;
}
if (term == NULL)
return 0;
term = deVar (term);
/* test whether we knew it before */
if (inKnowledge (know, term))
return 0;
if (isTermTuple (term))
{
knowledgeAddTerm (know, term->op1);
knowledgeAddTerm (know, term->op2);
}
/* adding variables? */
know->vars = termlistAddVariables (know->vars, term);
knowledgeSimplify (know, term);
if (isTermLeaf (term))
{
know->basic = termlistAdd (know->basic, term);
}
if (term->type == ENCRYPT)
{
Term invkey = inverseKey (know->inverses, term->key);
if (inKnowledge (know, invkey))
{
/* we can decrypt it */
knowledgeAddTerm (know, term->op);
if (!inKnowledge (know, term->key))
{
/* we know the op now, but not the key, so add it anyway */
know->encrypt = termlistAdd (know->encrypt, term);
}
}
else
{
/* we cannot decrypt it, and from the initial test we know we could not construct it */
know->encrypt = termlistAdd (know->encrypt, term);
}
termDelete (invkey);
}
return 1;
}
/*
Note: the input is a key k, i.e. it can decrypt
anything that was encrypted with k^{-1}.
*/
void
knowledgeSimplify (Knowledge know, Term key)
{
Termlist tldecrypts = NULL;
Termlist scan = know->encrypt;
Term invkey = inverseKey (know->inverses, key);
while (scan != NULL)
{
if (isTermEqual ((scan->term)->key, invkey))
{
tldecrypts = termlistAdd (tldecrypts, (scan->term)->op);
know->encrypt = termlistDelTerm (scan);
scan = know->encrypt;
}
else
scan = scan->next;
}
termDelete (invkey);
knowledgeAddTermlist (know, tldecrypts);
termlistDelete (tldecrypts);
}
/*
* Add a whole termlist.
*
* Returns true iff there was at least one new item.
*/
int
knowledgeAddTermlist (Knowledge know, Termlist tl)
{
int flag = 0;
while (tl != NULL)
{
flag = knowledgeAddTerm (know, tl->term) || flag;
tl = tl->next;
}
return flag;
}
/*
add an inverse pair to the knowledge
*/
void
knowledgeAddInverse (Knowledge know, Term t1, Term t2)
{
know->inverses = termlistAdd (know->inverses, t1);
know->inverses = termlistAdd (know->inverses, t2);
return;
}
/*
same, but for list. List pointer is simply copied, so don't delete it later!
*/
void
knowledgeSetInverses (Knowledge know, Termlist tl)
{
know->inverses = tl;
}
/*
inKnowledge
Is a term a part of the knowledge?
*/
int
inKnowledge (const Knowledge know, Term term)
{
/* if there is no term, then it's okay 'fur sure' */
if (term == NULL)
return 1;
/* if there is a term, but no knowledge, we're in trouble */
if (know == NULL)
return 0;
mindwipe (know, inKnowledge (know, term));
term = deVar (term);
if (isTermLeaf (term))
{
return inTermlist (know->basic, term);
}
if (term->type == ENCRYPT)
{
return inTermlist (know->encrypt, term) ||
(inKnowledge (know, term->key) && inKnowledge (know, term->op));
}
if (term->type == TUPLE)
{
return (inTermlist (know->encrypt, term) ||
(inKnowledge (know, term->op1) &&
inKnowledge (know, term->op2)));
}
return 0; /* unrecognized term type, weird */
}
int
isKnowledgeEqual (Knowledge know1, Knowledge know2)
{
if (know1 == NULL || know2 == NULL)
{
if (know1 == NULL && know2 == NULL)
return 1;
else
return 0;
}
if (!isTermlistEqual (know1->encrypt, know2->encrypt))
return 0;
return isTermlistEqual (know1->basic, know2->basic);
}
void
knowledgePrint (Knowledge know)
{
indent ();
if (know == NULL)
{
printf ("Empty.\n");
return;
}
printf (" [Basic]: ");
termlistPrint (know->basic);
printf ("\n");
indent ();
printf (" [Encrp]: ");
termlistPrint (know->encrypt);
printf ("\n");
indent ();
printf (" [Vars]: ");
termlistPrint (know->vars);
printf ("\n");
}
/*
print inverses
*/
void
knowledgeInversesPrint (Knowledge know)
{
Termlist tl;
int after = 0;
if (know == NULL)
{
printf ("Empty knowledge.");
return;
}
tl = knowledgeGetInverses (know);
if (tl == NULL)
{
printf ("None.");
}
else
{
while (tl != NULL && tl->next != NULL)
{
if (after)
{
printf (",");
}
printf ("(");
termPrint (tl->term);
printf (",");
termPrint (tl->next->term);
printf (")");
after = 1;
tl = tl->next->next;
}
}
}
/*
give the set of representatives for the knowledge.
Note: this is a shallow copy, and needs to be termlistDelete'd.
*/
Termlist
knowledgeSet (Knowledge know)
{
Termlist tl1, tl2;
tl1 = termlistShallow (know->basic);
tl2 = termlistShallow (know->encrypt);
return termlistConcat (tl1, tl2);
}
/*
get the inverses pointer of the knowledge.
Essentially the inverse function of knowledgeSetInverses
*/
Termlist
knowledgeGetInverses (Knowledge know)
{
if (know == NULL)
return NULL;
else
return know->inverses;
}
/*
* check whether any substitutions where made at all.
*/
int
knowledgeSubstNeeded (const Knowledge know)
{
Termlist tl;
if (know == NULL)
return 0;
tl = know->vars;
while (tl != NULL)
{
if (tl->term->subst != NULL)
return 1;
tl = tl->next;
}
return 0;
}
/*
* knowledgeReconstruction
*
* This is useful after e.g. substitutions.
* Just rebuilds the knowledge in a new (shallow) copy.
*/
Knowledge
knowledgeReconstruction (const Knowledge know)
{
Knowledge newknow = emptyKnowledge ();
newknow->inverses = know->inverses;
knowledgeAddTermlist (newknow, know->basic);
knowledgeAddTermlist (newknow, know->encrypt);
return newknow;
}
/*
* propagate any substitutions just made.
*
* This usually involves reconstruction of the complete knowledge, which is
* 'cheaper' than a thorough analysis, so we always make a copy.
*/
Knowledge
knowledgeSubstDo (const Knowledge know)
{
/* otherwise a copy (for deletion) is returned. */
return knowledgeReconstruction (know);
}
/*
* Undo the substitutions just made. Note that this does not work anymore after knowledgeSubstDo!
*/
void
knowledgeSubstUndo (const Knowledge know)
{
Termlist tl;
tl = know->vars;
while (tl != NULL)
{
tl->term->subst = NULL;
tl = tl->next;
}
}
/*
* knowledgeNew(old,new)
*
* yield a termlist (or NULL) that represents the reduced items that are
* in the new set, but not in the old one.
*/
Termlist
knowledgeNew (const Knowledge oldk, const Knowledge newk)
{
Termlist newtl;
newtl = NULL;
void addNewStuff (Termlist tl)
{
while (tl != NULL)
{
if (!inKnowledge (oldk, tl->term))
{
newtl = termlistAdd (newtl, tl->term);
}
tl = tl->next;
}
}
addNewStuff (newk->basic);
addNewStuff (newk->encrypt);
return newtl;
}

60
src/knowledge.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef KNOWLEDGE
#define KNOWLEDGE
#include "terms.h"
#include "termlists.h"
struct knowledge
{
Termlist basic;
Termlist encrypt;
Termlist inverses;
union
{
Termlist vars; // special: denotes unsubstituted variables
struct knowledge *next; // use for alternative memory management.
};
};
typedef struct knowledge *Knowledge;
void knowledgeInit (void);
void knowledgeDone (void);
Knowledge makeKnowledge ();
Knowledge emptyKnowledge ();
Knowledge knowledgeDuplicate (Knowledge know);
void knowledgeDelete (Knowledge know);
void knowledgeDestroy (Knowledge know);
int knowledgeAddTerm (Knowledge know, Term term);
int knowledgeAddTermlist (Knowledge know, Termlist tl);
void knowledgeAddInverse (Knowledge know, Term t1, Term t2);
void knowledgeSetInverses (Knowledge know, Termlist tl);
void knowledgeSimplify (Knowledge know, Term decryptkey);
int inKnowledge (const Knowledge know, Term term);
void knowledgePrint (Knowledge know);
void knowledgeInversesPrint (Knowledge know);
int isKnowledgeEqual (Knowledge know1, Knowledge know2);
Termlist knowledgeSet (Knowledge know);
Termlist knowledgeGetInverses (Knowledge know);
int knowledgeSubstNeeded (const Knowledge know);
Knowledge knowledgeSubstDo (const Knowledge know);
void knowledgeSubstUndo (const Knowledge know);
Termlist knowledgeNew (const Knowledge oldk, const Knowledge newk);
#define mindwipe(k,recurse) \
if (k != NULL && k->vars != NULL) { \
Termlist tl = k->vars; \
while (tl != NULL) { \
if (tl->term->subst != NULL) { \
Term oldsubst = tl->term->subst; \
tl->term->subst = NULL; \
int flag = recurse; \
tl->term->subst = oldsubst; \
return flag; \
} \
tl = tl->next; \
} \
} \
#endif

46
src/language.txt Normal file
View File

@ -0,0 +1,46 @@
Language
--------
language := (<def>)*
def := (<directive> | <protocol> | <rundef> | <unstrusted>)
//directive := <dir_require>
//dir_require := require <filename>;
protocol := protocol <protocolname> ( <rolelist> ) { <roledef>* } optsc
protocolname := <id>
intruderknow := public <termlist>;
roledef := role <rolename> { <actions> } optsc
rolename := <id>
actions := (<action>;)+
action := (<read> | <send> | <claim>)
decl := (<const> | <var>)+
const := const <termlist> [ : <typeterm> ];
var := var <termlist> [ : <typelist> ];
read := read [_<label>] (<term>,<term>,<term>);
send := send [_<label>] (<term>,<term>,<term>);
claim := claim [_<label>] (<term>,<termlist>);
label := <id>;
rundef := <protocolname>.<rolename> ( <instancelist> ) ;
instancelist := (<agent>|<typeterm>)*
agent := <term>
typeterm := <term>
typelist := <termlist>
untrusted := untrusted <termlist>;
termlist := <term> [, <termlist>]
term := (<baseterm> | <encterm> | <tupleterm> | <function>)
encterm := { <term> } <term>
function := <term> ( <term> )
baseterm := (<variable> | <const>)
variable := <id>
const := <id>
optsc := [ ; ]
id := (<digit>|<uppercase>|<lowercase>)+

797
src/latex.c Normal file
View File

@ -0,0 +1,797 @@
/*
* LaTeX output component
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#include "runs.h"
#include "memory.h"
#include "modelchecker.h"
#include "tracebuf.h"
#include "varbuf.h"
#include "output.h"
#define EVENTSPACE 1
#define LINKTHRESHOLD 0.95
extern const char *progname;
extern const char *releasetag;
extern int globalLatex;
extern Term TERM_Function;
/* struct for additional info */
struct traceinfo {
int match;
int position;
};
/* global variables for this module */
struct traceinfo *tinfo;
int width;
int landscape = 0;
int *runPerm;
/* code */
void latexInit(const System sys, int argc, char **argv)
{
int i;
printf("\\documentclass{article}\n");
printf("\\usepackage{msc}\n");
printf("%%\n");
printf("%% LaTeX output generated by %s\n", progname);
printf("%% Input:\n");
/* print command line */
printf("%% $");
for (i = 0; i < argc; i++)
printf(" %s", argv[i]);
printf("\n");
printf("%%\n");
printf("\\begin{document}\n\n");
/* comment macro (used for debugging) */
printf("\\newcommand{\\comment}[1]{}\n");
/* preamble */
printf("\\input{preamble}\n");
}
void latexDone(const System sys)
{
printf("\\input{postamble}\n");
printf("\n\\end{document}\n\n");
}
void
latexTermPrint (Term term, Termlist highlight)
{
if (term == NULL)
{
printf ("Empty term");
return;
}
#ifdef DEBUG
if (!DEBUGL (1))
{
term = deVar (term);
}
#else
term = deVar (term);
#endif
if (realTermLeaf (term))
{
if (inTermlist(highlight, term))
printf("\\mathbf{");
symbolPrint (term->symb);
if (realTermVariable (term))
printf ("V");
if (term->runid >= 0)
{
printf ("\\sharp%i", term->runid);
}
if (term->subst != NULL)
{
printf ("\\rightarrow");
latexTermPrint (term->subst, highlight);
}
if (inTermlist(highlight, term))
printf("}");
}
if (realTermTuple (term))
{
printf ("(");
while (realTermTuple (term))
{
latexTermPrint (term->op1, highlight);
printf (",");
term = term->op2;
if (!realTermTuple (term))
latexTermPrint (term, highlight);
}
printf (")");
return;
}
if (realTermEncrypt (term))
{
if (isTermLeaf (term->key)
&& inTermlist (term->key->stype, TERM_Function))
{
/* function application */
latexTermPrint (term->key, highlight);
printf ("(");
latexTermPrint (term->op, highlight);
printf (")");
}
else
{
/* normal encryption */
printf ("\\{");
latexTermPrint (term->op, highlight);
printf ("\\}_{");
latexTermPrint (term->key, highlight);
printf ("}");
}
}
}
void
latexTermlistPrint (Termlist tl, Termlist highlight)
{
if (tl == NULL)
{
printf ("[Empty]");
return;
}
printf ("[");
while (tl != NULL)
{
latexTermPrint (tl->term, highlight);
tl = tl->next;
if (tl != NULL)
printf(", ");
}
printf ("]");
}
void latexTimers(const System sys)
{
void endline(void) {
printf("\\\\ \\hline\n");
}
printf("\\begin{tabular}{|r|r|c|r|} \\hline\n");
/* display stats, header first */
printf("Time & States & Attack & st/sec");
endline();
/* print time */
double seconds;
seconds = (double) clock() / CLOCKS_PER_SEC;
printf("$%.3e$ &", seconds);
/* states traversed */
printf("$");
statesPrintShort(sys);
printf("$ &");
/* flag
*
* L n Attack of length <n>
* None failed claim
* NoClaim no claims
*/
if (sys->claims == 0) {
printf("NoClaim & ");
} else {
if (sys->failed > 0)
printf("L:%i & ", attackLength(sys->attack));
else
printf("None & ");
}
/*
printf("%.3e (%li) claims encountered.\n",(double)
sys->claims, sys->claims);
printf("%.3e (%li) claims failed.\n",(double)
sys->failed, sys->failed);
*/
/* states per second */
if (seconds > 0) {
printf("$%.3e$ ",
(double) (sys->statesLow +
(sys->statesHigh * ULONG_MAX)) / seconds);
} else {
printf("$\\infty$ ");
}
endline();
printf("\\end{tabular}\n\n");
}
void latexMSCStart()
{
if (landscape)
printf("\\begin{landscape}\n");
printf("\\begin{msc}{attack}\n");
}
void latexMSCEnd()
{
printf("\\end{msc}\n");
if (landscape)
printf("\\end{landscape}\n");
}
void latexDeclInst(const System sys, int run)
{
Term bar = NULL;
bar = agentOfRun(sys, run);
printf("\\declinst{run%d}{$", run);
termPrint(bar);
printf("\\sharp%i$}{$", run);
agentsOfRunPrint(sys, run);
printf("$}\n");
}
void latexEventSpace(int amount)
{
int i;
//printf("%% number of newlines: %d\n",amount);
for (i = 0; i < EVENTSPACE * amount; i++)
printf("\\nextlevel\n");
}
void latexMessagePrint(struct tracebuf *tb, int from, int to)
{
Term sendTerm = NULL;
Term readTerm = NULL;
if (from == -1 && to == -1) {
return;
}
if (from != -1) {
sendTerm = tb->event[from]->message;
}
if (to != -1) {
readTerm = tb->event[to]->message;
}
if (from == -1 && to != -1) {
printf("\\found{$");
termPrint(readTerm);
printf("$}{}{run%d}\n", tb->run[to]);
} else if (from != -1 && to == -1) {
printf("\\lost{$");
termPrint(sendTerm);
printf("$}{}{run%d}\n", tb->run[from]);
} else if (from != -1 && to != -1) {
printf("\\mess{$");
termPrint(sendTerm);
if (!isTermEqual(sendTerm, readTerm)) {
printf("\\rightarrow");
termPrint(readTerm);
}
printf("$}{run%d", tb->run[from]);
printf("}{run%d}[%d]", tb->run[to],
EVENTSPACE * (tinfo[to].position -
tinfo[from].position));
printf("\n");
}
}
void latexMessagePrintHighlight(struct tracebuf *tb, int from, int to, Termlist highlight)
{
Term sendTerm = NULL;
Term readTerm = NULL;
if (from == -1 && to == -1) {
return;
}
if (from != -1) {
sendTerm = tb->event[from]->message;
}
if (to != -1) {
readTerm = tb->event[to]->message;
}
if (from == -1 && to != -1) {
printf("\\found{$");
latexTermPrint(readTerm, highlight);
printf("$}{}{run%d}\n", tb->run[to]);
} else if (from != -1 && to == -1) {
printf("\\lost{$");
latexTermPrint(sendTerm, highlight);
printf("$}{}{run%d}\n", tb->run[from]);
} else if (from != -1 && to != -1) {
printf("\\mess{$");
latexTermPrint(sendTerm, highlight);
if (!isTermEqual(sendTerm, readTerm)) {
printf("\\rightarrow");
latexTermPrint(readTerm, highlight);
}
printf("$}{run%d", tb->run[from]);
printf("}{run%d}[%d]", tb->run[to],
EVENTSPACE * (tinfo[to].position -
tinfo[from].position));
printf("\n");
}
}
void latexLearnComment(struct tracebuf *tb, int index, Termlist tl)
{
printf("\\msccomment[4ex]{$I_%d=I_%d\\oplus ", index + 1,
index);
termlistPrint(tl);
printf("$}{envright}\n");
}
void latexAction(struct tracebuf *tb, int te)
{
printf("\\action{$");
termPrint(tb->event[te]->message);
printf("$}{run%d}\n", tb->run[te]);
//printf("\\nextlevel\n");
}
void latexClaim(struct tracebuf *tb, int run, Termlist tl)
{
printf("\\condition{$");
printf("\\neg secret ");
termlistPrint(tl);
printf("$}{run%d}\n", run);
}
int latexCorrespondingSend(struct tracebuf *tb, int rd)
{
int labelMatch = 0;
int toMatch = 0;
int fromMatch = 0;
int tofromMatch = 0;
int messageMatch = 0;
int nMatches = 0;
int maxNMatches = 0;
int readEvent = rd;
int sendEvent = -1;
int bestSendEvent = -1;
for (sendEvent = readEvent; sendEvent >= 0; sendEvent--) {
if (tb->event[sendEvent]->type == SEND) {
/* do all the different kind of matchings first */
labelMatch =
isTermEqual(tb->event[sendEvent]->label,
tb->event[readEvent]->label);
toMatch =
isTermEqual(tb->event[sendEvent]->to,
tb->event[readEvent]->to);
fromMatch =
isTermEqual(tb->event[sendEvent]->from,
tb->event[readEvent]->from);
tofromMatch = toMatch || fromMatch;
messageMatch =
isTermEqual(tb->event[sendEvent]->message,
tb->event[readEvent]->message);
/* calculate the score */
nMatches = labelMatch + tofromMatch + messageMatch;
if (nMatches == 3) {
/* bingo! success on all matches */
//printf("Found perfect match: %d\n", s);
bestSendEvent = sendEvent;
break;
}
if (nMatches > maxNMatches) {
if (labelMatch && messageMatch) {
/* strongest restriction: message and label should match */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
} else if (messageMatch) {
/* if label AND message don't match: */
/* at least message should match */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
} else if (labelMatch) {
/* if message doesn't match */
/* the label should matches */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
}
}
}
}
//bestSendEvent = NULL;
if (bestSendEvent == -1) {
int u;
for (u = 0; u < rd; u++) {
if (tb->event[u]->type == SEND) {
//knowledgePrint(sys->traceKnow[u]);
if (inKnowledge
(tb->know[u + 1], tb->event[readEvent]->message)) {
bestSendEvent = u;
break;
}
}
}
}
if (bestSendEvent == -1) {
printf("%% Could not find a matching SEND\n");
}
return bestSendEvent;
}
int
newInKnowledge (const Knowledge know, Term term)
{
/* if there is no term, then it's okay 'fur sure' */
if (term == NULL)
return 1;
/* if there is a term, but no knowledge, we're in trouble */
if (know == NULL)
return 0;
mindwipe (know, inKnowledge (know, term));
term = deVar (term);
if (isTermLeaf (term))
{
return inTermlist (know->basic, term);
}
if (term->type == ENCRYPT)
{
return inTermlist (know->encrypt, term) ||
(inKnowledge (know, term->key) || inKnowledge (know, term->op));
}
if (term->type == TUPLE)
{
return (inTermlist (know->encrypt, term) ||
(inKnowledge (know, term->op1) ||
inKnowledge (know, term->op2)));
}
return 0; /* unrecognized term type, weird */
}
int latexCorrespondingSend2(struct tracebuf *tb, int readEvent)
{
int u;
for (u = tb->length - 1; u>=0 ; u--)
{
if (tb->event[u]->type == SEND)
{
if (!inKnowledge (tb->know[u], tb->event[readEvent]->message))
{
/*
printf("%% term[");
printf("]#%d is introduced at traceEvent[%d] ",readEvent,u);
printf("\n");
*/
return u;
}
}
}
return -1;
}
/*
* Display knowledge in LaTeX format.
*/
void knowledgePrintLatex(Knowledge know)
{
Termlist tl;
if (know == NULL)
{
printf("\\emptyset");
}
else
{
tl = knowledgeSet(know);
termlistPrint(tl);
termlistDelete(tl);
}
}
void attackDisplayLatex(System sys)
{
int i;
struct tracebuf *tb;
int *runPosition;
int currRun;
int position;
int eventSize;
Termlist tl;
Termlist newtl;
Termlist claimDetails;
Termlist highlights = NULL;
int cKnowledge;
int bestSend;
tb = sys->attack;
if (tb == NULL) {
printf("Attack pointer empty: nothing to display.\n");
exit(1);
}
/* set variables */
varbufSet (sys, tb->variables);
/* Rebuild knowledge. Strange, this ought to be good.
* Maybe reconstruct dependencies as well. */
tracebufRebuildKnow(tb);
/* Make a comment in which the trace is displayed, for debugging etc. */
printf("\n\\comment{ TRACE\n\n");
printf("Length: %i\n",tb->length);
printf("Reallength: %i\n",tb->reallength);
printf("\n");
i = 0;
while (i <= tb->length)
{
printf("Knowledge %i:\n",i);
knowledgePrint(tb->know[i]);
printf(" [Inverses]: ");
knowledgeInversesPrint(tb->know[i]);
printf("\n\n");
if (i < tb->length)
{
printf("Event %i\t[",i);
switch (tb->status[i])
{
case S_UNK:
printf("?");
break;
case S_RED:
printf("redundant");
break;
case S_TOD:
printf("to do");
break;
case S_OKE:
printf("okay");
break;
default:
printf("illegal status code");
break;
}
printf("]\t");
termPrint(tb->event[i]->message);
printf("\t#%i",tb->run[i]);
printf("\n");
roledefPrint(tb->event[i]);
printf("\n\n");
}
i++;
}
printf("}\n\n");
/* display initial knowledge */
printf("$I_0 = \\emptyset \\oplus ");
knowledgePrintLatex(tb->know[0]);
printf("$\n\n");
tinfo =
(struct traceinfo *) memAlloc((tb->length+1) *
sizeof(struct traceinfo));
width = 1;
for (i = 0; i < tb->length; i++) {
if (tb->run[i] >= width)
width = tb->run[i] + 1;
}
for (i = 0; i < tb->length; i++) {
tb->link[i] = -1;
tinfo[i].match = -1;
tinfo[i].position = i;
}
tinfo[i].match = -1;
tinfo[i].position = i;
runPosition = (int *) memAlloc(width * sizeof(int));
for (i = 0; i < width; i++) {
runPosition[i] = 0;
}
for (i = tb->length - 1; i >= 0; i--)
{
if (tb->status[i] != S_RED)
{
if (tb->event[i]->type == READ && !tb->event[i]->internal)
{
bestSend = latexCorrespondingSend2(tb, i);
printf("%% match: %d <-> %d\n",i, bestSend);
if (bestSend == -1)
continue;
tb->link[i] = bestSend;
tb->link[bestSend] = i;
}
if (tb->event[i]->type == CLAIM)
{
claimDetails = claimViolationDetails(sys, tb->run[i], tb->event[i], tb->know[i]);
}
}
}
printf("\\comment{ claimDetails :\n");
termlistPrint(claimDetails);
printf("\n}\n");
// landscape = (width > 4); // not for the time being
position = 0;
currRun = 0;
eventSize = 0;
for (i = 0; i < tb->length; i++)
{
if (tb->status[i] != S_RED)
{
tinfo[i].position = position;
eventSize = 1;
currRun = tb->run[i];
switch (tb->event[i]->type) {
case SEND:
position++;
tinfo[i].position++;
break;
case READ:
if (tb->link[i] != -1) {
if (termDistance(tb->event[i]->message,tb->event[tb->link[i]]->message) < LINKTHRESHOLD)
{
/* disconnect read-send */
tb->link[tb->link[i]] = -1;
tb->link[i] = -1;
} else {
if (runPosition[currRun] <= tinfo[tb->link[i]].position &&
currRun != tb->run[tb->link[i]])
{
printf("\\comment{\n");
termPrint(tb->event[i]->message);
printf("\n");
termPrint(tb->event[tb->link[i]]->message);
printf("\n");
printf("%% termDistance: %f\n",
termDistance(tb->event[i]->message,
tb->event[tb->link[i]]->message));
printf("}\n");
tinfo[i].position = tinfo[tb->link[i]].position;
eventSize = 0;
}
}
}
if (tb->event[i]->internal) {
eventSize = 0;
}
break;
case CLAIM:
if (claimDetails != NULL && claimDetails != (Termlist) -1) {
eventSize = 2;
} else {
eventSize = 0;
}
break;
default:
break;
}
if (!(tb->event[i]->type == READ && tb->event[i]->internal))
runPosition[currRun] = tinfo[i].position + eventSize;
/* printf("%% Event %d at %d\n", i, position); */
position += eventSize;
}
}
latexMSCStart();
for (i = 0; i < width; i++) {
if (runPosition[i] > 0)
latexDeclInst(sys, i);
}
//for (j=-1; j<=sys->step; j++)
position = 0;
cKnowledge = 0;
for (i = 0; i < tb->length; i++)
{
if (tb->status[i] != S_RED)
{
latexEventSpace(tinfo[i].position - position);
if (tinfo[i].position >= position)
{
position = tinfo[i].position;
}
switch (tb->event[i]->type) {
case SEND:
newtl = knowledgeNew(tb->know[i], tb->know[i + 1]);
highlights = NULL;
/* Build a Termlist of terms that from the claimViolationDetails,
that appear in the knowledge */
if (newtl != NULL)
{
tl = claimDetails;
while (tl != NULL)
{
if (inTermlist(newtl, tl->term))
{
highlights = termlistAdd(highlights, tl->term);
}
tl = tl->next;
}
printf("\\msccomment[4ex]{$I_%d=I_%d\\oplus ", cKnowledge + 1,
cKnowledge);
cKnowledge++;
latexTermlistPrint(newtl, highlights);
printf("$}{envright}\n");
}
if (tb->link[i] != -1 && i < tb->length) {
latexMessagePrintHighlight(tb, i, tb->link[i], highlights);
} else {
latexMessagePrintHighlight(tb, i, -1, highlights); //lost message
}
termlistDelete(highlights);
break;
case READ:
if (tb->event[i]->internal) {
} else if (tb->link[i] == -1) {
latexMessagePrint(tb, -1, i); //found message
}
break;
case CLAIM:
if (claimDetails != NULL && claimDetails != (Termlist) -1) {
latexClaim(tb, tb->run[i], claimDetails);
}
break;
default:
break; //kannie!
}
}
}
latexEventSpace(2);
latexMSCEnd();
memFree(runPosition, width * sizeof(int));
memFree(tinfo, (tb->length+1) * sizeof(struct traceinfo));
}

21
src/latex.h Normal file
View File

@ -0,0 +1,21 @@
/*
* LaTeX output component header
*/
#ifndef LATEX
#define LATEX
#include "runs.h"
void latexInit(const System sys, int argc, char **argv);
void latexDone(const System sys);
void latexTimers(const System sys);
void latexMSCStart();
void latexMSCEnd();
void latexDeclInst(const System sys);
void latexMessagePrint(const System sys, int from, int to);
void latexLearnComment(const System sys, Termlist tl);
void latexTracePrint(System sys);
void attackDisplayLatex(System sys);
#endif

4
src/license.txt Normal file
View File

@ -0,0 +1,4 @@
- GNU getopt
- GNU bison/flex
- ARGTABLE http://argtable.sourceforge.net/
- de rest (c) Cas

1
src/lutger-todo.txt Normal file
View File

@ -0,0 +1 @@
- TODO vullen

548
src/main.c Normal file
View File

@ -0,0 +1,548 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include "runs.h"
#include "debug.h"
#include "modelchecker.h"
#include "memory.h"
#include "symbols.h"
#include "pheading.h"
#include "symbols.h"
#include "tok.h"
#include "tac.h"
#include "compiler.h"
#include "latex.h"
#include "output.h"
#include "argtable2.h"
extern struct tacnode *spdltac;
void scanner_cleanup (void);
void strings_cleanup (void);
int yyparse (void);
void MC_incRuns (const System sys);
void MC_incTraces (const System sys);
void MC_single (const System sys);
int modelCheck (const System sys);
const char *progname = "scyther";
const char *releasetag = "alpha2-devel";
int
main (int argc, char **argv)
{
System sys;
struct arg_int *traversal = arg_int0 ("t", "traverse", NULL,
"set traversal method, partial order reduction (default is 8)");
struct arg_rem *trav1 = arg_rem (NULL, "1 : nondeterministic.");
struct arg_rem *trav2 = arg_rem (NULL, "2 : nonreads first.");
struct arg_rem *trav3 = arg_rem (NULL, "3 : nonreads; supertransition.");
struct arg_rem *trav4 =
arg_rem (NULL, "4 : nonreads; supertransition; forbidden");
struct arg_rem *trav5 = arg_rem (NULL,
"5 : nonreads; supertransition; forbidden; remove hopeless");
struct arg_rem *trav6 =
arg_rem (NULL, "6 : secrecy p.o. reduction, new style");
struct arg_rem *trav7 = arg_rem (NULL,
"7 : nonreads; supertransition; forbidden; remove hopeless V2");
struct arg_rem *trav8 =
arg_rem (NULL, "8 : nondeterministic knowledge brancher");
struct arg_int *match =
arg_int0 ("m", "match", NULL, "matching method (default is 0)");
struct arg_rem *match0 = arg_rem (NULL, "0 : typed.");
struct arg_rem *match1 = arg_rem (NULL, "1 : basic typeflaws.");
struct arg_rem *match2 = arg_rem (NULL, "2 : full typeflaws");
struct arg_lit *clp =
arg_lit0 ("c", "cl", "use constraint logic, non-associative.");
struct arg_int *prune = arg_int0 ("p", "prune", NULL,
"pruning method (default is 2)");
struct arg_rem *prune0 =
arg_rem (NULL, "0 : search all traces, no pruning.");
struct arg_rem *prune1 = arg_rem (NULL,
"1 : search traces of any length until a violation occurs.");
struct arg_rem *prune2 = arg_rem (NULL,
"2 : search progessively shorter traces after a violated claim.");
struct arg_rem *prune3 = arg_rem (NULL, "3 : quit after a violated claim.");
struct arg_int *maxlength = arg_int0 ("l", "max-length", NULL,
"prune traces longer than <int> events.");
struct arg_lit *incTraces = arg_lit0 (NULL, "increment-traces",
"incremental search using the length of the traces.");
struct arg_int *maxruns =
arg_int0 ("r", "max-runs", NULL, "create at most <int> runs.");
struct arg_lit *incRuns = arg_lit0 (NULL, "increment-runs",
"incremental search using the number of runs.");
struct arg_lit *latex = arg_lit0 (NULL, "latex", "output in LaTeX format.");
struct arg_lit *noreport =
arg_lit0 ("d", "disable-report", "don't report violations.");
struct arg_int *switchS = arg_int0 ("s", "states", NULL,
"report total number of states and claims traversed.");
struct arg_rem *switchS0 =
arg_rem (NULL, "if <int> is not 0, report progress after <int> states.");
// struct arg_file *outfile = arg_file0("o",NULL,"<output>", "output file (default is \"-\")");
#ifdef DEBUG
struct arg_int *porparam = arg_int0 (NULL, "pp", NULL, "POR parameter.");
struct arg_lit *switchI = arg_lit0 ("I", "debug-indent",
"indent the debug output using trace length.");
struct arg_int *debugl =
arg_int0 ("D", "debug", NULL, "set debug level (default is 0)");
#endif
struct arg_lit *help = arg_lit0 (NULL, "help", "print this help and exit");
struct arg_lit *version =
arg_lit0 (NULL, "version", "print version information and exit");
//struct arg_file *infiles = arg_filen(NULL,NULL,"FILE",0,argc+2, "input file(s)");
struct arg_end *end = arg_end (30);
void *argtable[] = {
traversal, trav1, trav2, trav3, trav4, trav5, trav6, trav7, trav8,
match, match0, match1, match2,
clp,
prune, prune0, prune1, prune2, prune3,
maxlength, incTraces,
maxruns, incRuns,
latex,
noreport,
switchS, switchS0,
#ifdef DEBUG
porparam,
switchI,
debugl,
#endif
help, version,
// infiles,
end
};
int nerrors;
int exitcode = 0;
/* verify the argtable[] entries were allocated sucessfully */
if (arg_nullcheck (argtable) != 0)
{
/* NULL entries were detected, some allocations must have failed */
printf ("%s: insufficient memory\n", progname);
exitcode = 1;
goto exit;
}
/* defaults
* set any command line default values prior to parsing */
#ifdef DEBUG
debugl->ival[0] = 0;
porparam->ival[0] = 0;
#endif
traversal->ival[0] = 8;
match->ival[0] = 0;
maxlength->ival[0] = -1;
maxruns->ival[0] = INT_MAX;
prune->ival[0] = 2;
switchS->ival[0] = 0;
/* Parse the command line as defined by argtable[] */
nerrors = arg_parse (argc, argv, argtable);
/* special case: '--help' takes precedence over error reporting */
if (help->count > 0)
{
printf ("Usage: %s ", progname);
arg_print_syntax (stdout, argtable, "\n");
printf
("This program can model check security protocols for various\n");
printf ("properties, given a finite scenario.\n\n");
arg_print_glossary (stdout, argtable, " %-25s %s\n");
exitcode = 0;
goto exit;
}
/* special case: '--version' takes precedence error reporting */
if (version->count > 0)
{
printf ("'%s' model checker for security protocols.\n", progname);
printf ("%s release.\n", releasetag);
#ifdef DEBUG
printf ("Compiled with debugging support.\n");
#endif
printf ("December 2003--, Cas Cremers\n");
exitcode = 0;
goto exit;
}
/* If the parser returned any errors then display them and exit */
if (nerrors > 0)
{
/* Display the error details contained in the arg_end struct. */
arg_print_errors (stdout, end, progname);
printf ("Try '%s --help' for more information.\n", progname);
exitcode = 1;
goto exit;
}
/* special case: uname with no command line options induces brief help */
/*
if (argc==1)
{
printf("Try '%s --help' for more information.\n",progname);
exitcode=0;
goto exit;
}
*/
/*
* Arguments have been parsed by argtable,
* continue with main code.
*/
/* Lutger-tries-to-test-with-broken-methods detector */
if (clp->count > 0)
{
printf ("For the time being, this method is not supported, \n");
printf ("as too many changes have been made to the normal \n");
printf ("matching logic, and CL simply isn't reliable in \nmany ");
printf ("ways. Try again in a few weeks.\n");
exit(0);
}
/* handle debug level */
#ifdef DEBUG
debugSet (debugl->ival[0]);
if (DEBUGL (1))
{
/* print command line */
int i;
printf ("$");
for (i = 0; i < argc; i++)
printf (" %s", argv[i]);
printf ("\n");
}
#else
debugSet (0);
#endif
/* Initialize memory routines */
memInit ();
/* initialize symbols */
termsInit ();
termlistsInit ();
knowledgeInit ();
symbolsInit ();
tacInit ();
/* generate system */
sys = systemInit ();
#ifdef DEBUG
sys->porparam = porparam->ival[0];
#endif
sys->latex = latex->count;
sys->know = emptyKnowledge ();
/* parse input */
yyparse ();
#ifdef DEBUG
if (DEBUGL (1))
tacPrint (spdltac);
#endif
/* compile */
compile (sys, spdltac, maxruns->ival[0]);
scanner_cleanup ();
#ifdef DEBUG
if (DEBUGL (1))
{
printf ("\nCompilation yields:\n\n");
printf ("untrusted agents: ");
termlistPrint (sys->untrusted);
printf ("\n");
knowledgePrint (sys->know);
printf ("inverses: ");
knowledgeInversesPrint (sys->know);
printf ("\n");
locVarPrint (sys->locals);
protocolsPrint (sys->protocols);
printf ("\nInstantiated runs:\n\n");
runsPrint (sys);
}
#endif
/* allocate memory for traces, based on runs */
systemStart (sys);
sys->traceKnow[0] = sys->know; // store initial knowledge
/* add parameters to system */
sys->clp = (clp->count > 0 ? 1 : 0);
sys->traverse = traversal->ival[0];
sys->match = match->ival[0];
sys->prune = prune->ival[0];
sys->switchS = switchS->ival[0];
/* TODO for now, warning for -m2 and non-clp */
if (sys->match == 2 && !sys->clp)
{
printf
("Warning: -m2 is only supported for constraint logic programming.\n");
}
#ifdef DEBUG
/* in debugging mode, some extra switches */
if (switchI->count > 0)
indentActivate ();
if (DEBUGL (1))
printf ("Using traversal method %i.\n", sys->traverse);
#else
/* non-debug defaults */
sys->switchM = 0;
#endif
if (noreport->count > 0)
sys->report = 0;
if (maxlength->ival[0] >= 0)
sys->switch_maxtracelength = maxlength->ival[0];
/* latex header? */
if (sys->latex)
latexInit (sys, argc, argv);
/* model check system */
#ifdef DEBUG
if (DEBUGL (1))
printf ("Start modelchecking system.\n");
#endif
if (incRuns->count > 0)
{
MC_incRuns (sys);
}
else
{
if (incTraces->count > 0)
{
MC_incTraces (sys);
}
else
{
MC_single (sys);
}
}
/* Display shortest attack, if any */
if (sys->attack != NULL && sys->attack->length != 0)
{
attackDisplay(sys);
}
/* latex closeup */
if (sys->latex)
latexDone (sys);
/*
* Now we clean up any memory that was allocated.
*/
knowledgeDestroy (sys->know);
systemDone (sys);
/* done symbols */
tacDone ();
symbolsDone ();
knowledgeDone ();
termlistsDone ();
termsDone ();
/* memory clean up? */
strings_cleanup ();
memDone ();
exit:
/* deallocate each non-null entry in argtable[] */
arg_free (argtable);
return exitcode;
}
void
timersPrint (const System sys)
{
/* display stats, header first */
printf ("Time\t\tStates\t\tAttack\t\tst/sec\n");
/* print time */
double seconds;
seconds = (double) clock () / CLOCKS_PER_SEC;
printf ("%.3e\t", seconds);
/* states traversed */
statesPrintShort (sys);
printf ("\t");
/* flag
*
* L n Attack of length <n>
* None failed claim
* NoClaim no claims
*/
if (sys->claims == 0)
{
printf ("NoClaim\t\t");
}
else
{
if (sys->failed > 0)
printf ("L:%i\t\t", attackLength(sys->attack));
else
printf ("None\t\t");
}
/*
printf("%.3e (%li) claims encountered.\n",(double)
sys->claims, sys->claims);
printf("%.3e (%li) claims failed.\n",(double)
sys->failed, sys->failed);
*/
/* states per second */
if (seconds > 0)
{
printf ("%.3e\t",
(double) (sys->statesLow +
(sys->statesHigh * ULONG_MAX)) / seconds);
}
else
{
printf ("<inf>\t\t");
}
printf ("\n");
}
/*
* Analyse the model.
*
* This procedure considers mainly incremental searches, and settings
* parameters for that. The real work is handled by modelCheck.
*/
void
MC_incRuns (const System sys)
{
/*
* incremental runs check
*
* note: we assume that at least one run needs to be checked.
*/
int maxruns = sys->maxruns;
int runs = 1;
int flag = 1;
int res;
do
{
systemReset (sys);
sys->maxruns = runs;
printf ("%i of %i runs in incremental runs search.\n", runs, maxruns);
res = modelCheck (sys);
printf ("\n");
if (res)
{
/* Apparently a violation occurred. If we are searching
* the whole space, then we just continue. However, if
* we're looking to prune, ``the buck stops here''. */
if (sys->prune != 0)
{
flag = 0;
}
}
runs++;
}
while (flag && runs <= maxruns);
}
void
MC_incTraces (const System sys)
{
/*
* incremental traces check
*
* note: we assume that at least one run needs to be checked.
*/
int maxtracelen;
int tracelen;
int tracestep;
tracestep = 3; /* what is a sensible stepping size? */
maxtracelen = getMaxTraceLength (sys);
tracelen = maxtracelen - tracestep;
while (tracelen > 6) /* what is a reasonable minimum? */
tracelen -= tracestep;
int flag = 1;
int res;
do
{
systemReset (sys);
sys->maxtracelength = tracelen;
printf ("%i of %i trace length in incremental trace length search.\n",
tracelen, maxtracelen);
res = modelCheck (sys);
printf ("\n");
if (res)
{
/* Apparently a violation occurred. If we are searching
* the whole space, then we just continue. However, if
* we're looking to prune, ``the buck stops here''. */
if (sys->prune != 0)
{
flag = 0;
}
}
tracelen += tracestep;
}
while (flag && tracelen <= maxtracelen);
}
/*
* Traditional handywork
*/
void
MC_single (const System sys)
{
/*
* simple one-time check
*/
systemReset (sys); // reset any globals
modelCheck (sys);
}
/*
* Model check the system, given all parameters.
*
* Precondition: the system was reset with the corresponding parameters.
* This also reports on time and states traversed.
*/
int
modelCheck (const System sys)
{
traverse (sys); // start model checking
if (sys->latex)
{
latexTimers (sys);
}
else
{
timersPrint (sys);
}
return (sys->failed);
}

298
src/match_basic.c Normal file
View File

@ -0,0 +1,298 @@
#include <stdlib.h>
#include <stdio.h>
#include "memory.h"
#include "substitutions.h"
#include "runs.h"
#include "modelchecker.h"
#include "match_basic.h"
Termlist
candidates (const Knowledge know)
{
Termlist knowset;
Termlist candlist;
/* candidates for typeless basic stuff */
knowset = knowledgeSet (know);
candlist = termlistAddBasics (NULL, knowset);
termlistDelete (knowset);
return candlist;
}
struct fvpass
{
int (*solution) (struct fvpass, Knowledge);
System sys;
int run;
Roledef roledef;
int (*proceed) (System, int);
};
/*
* fix variables in a message, and check whether it can be accepted.
*
* fp.sys is only accessed for the matching type.
*/
int
fixVariablelist (const struct fvpass fp, const Knowledge know,
Termlist varlist, const Term message)
{
int flag = 0;
Termlist tlscan;
Termlist candlist;
if (varlist != NULL)
{
if (!isTermVariable (varlist->term))
{
while (varlist != NULL && !isTermVariable (varlist->term))
{
varlist = varlist->next;
}
}
}
/* cond: varlist == NULL || isTermvariable(varlist->term) */
if (varlist == NULL)
{
/* there are no (more) variables to be fixed. */
/* actually trigger it if possible */
int copied;
Knowledge tempknow;
/* first we propagate the substitutions in the knowledge */
/* TODO this must also be done for all agent knowledge!! */
if (knowledgeSubstNeeded (know))
{
copied = 1;
tempknow = knowledgeSubstDo (know);
}
else
{
copied = 0;
tempknow = know;
}
if (inKnowledge (tempknow, message))
{
if (fp.solution != NULL)
{
flag = fp.solution (fp, tempknow);
}
else
{
flag = 1;
}
}
else
flag = 0;
/* restore state */
if (copied)
{
knowledgeDelete (tempknow);
knowledgeSubstUndo (know);
}
return flag;
}
/* cond: isTermvariable(varlist->term) */
varlist->term = deVar (varlist->term);
/* cond: realTermvariable(varlist->term) */
candlist = candidates (know);
#ifdef DEBUG
if (DEBUGL (5))
{
indent ();
printf ("Set ");
termPrint (varlist->term);
printf (" with type ");
termlistPrint (varlist->term->stype);
printf (" from candidates ");
termlistPrint (candlist);
printf ("\n");
}
#endif
/* Now check all candidates. Do they work as candidates? */
tlscan = candlist;
while (tlscan != NULL && !(flag && fp.solution == NULL))
{
if (!isTermEqual (varlist->term, tlscan->term))
{
/* substitute */
varlist->term->subst = tlscan->term;
if (validSubst (fp.sys->match, varlist->term))
{
#ifdef DEBUG
if (DEBUGL (5))
{
indent ();
printf ("Substituting ");
termPrint (varlist->term);
printf ("\n");
}
#endif
/* now we may need to substitute more */
flag = fixVariablelist (fp, know, varlist->next, message)
|| flag;
}
}
tlscan = tlscan->next;
}
/* restore state: variable is not instantiated. */
varlist->term->subst = NULL;
/* garbage collect */
termlistDelete (candlist);
return flag;
}
/*
* check whether a roledef, given some newer knowledge substitutions, can survive
*/
#define enabled_basic(sys,know,newterm) !inKnowledge(know,newterm)
/*
* matchRead
*
* try to execute a read event. It must be able to be construct it from the
* current intruder knowledge (Inject), but not from the forbidden knowledge
* set, which we tried earlier.
*
* returns 0 if it is not enabled, 1 if it was enabled (and routes explored)
*/
int
matchRead_basic (const System sys, const int run,
int (*proceed) (System, int))
{
Roledef rd;
int flag = 0;
struct fvpass fp;
int solution (struct fvpass fp, Knowledge know)
{
Knowledge oldknow;
Term newterm;
/* remove variable linkages */
newterm = termDuplicateUV (fp.roledef->message);
/* a candidate, but if this is a t4 traversal, is it also an old one? */
if (fp.sys->traverse < 4 ||
fp.roledef->forbidden == NULL ||
enabled_basic (fp.sys, fp.roledef->forbidden, newterm))
{
/* it is enabled, i.e. not forbidden */
oldknow = fp.sys->know;
fp.sys->know = know;
#ifdef DEBUG
if (DEBUGL (5))
{
printf ("+");
}
#endif
fp.proceed (fp.sys, fp.run);
fp.sys->know = oldknow;
termDelete (newterm);
return 1;
}
else
{
/* blocked */
#ifdef DEBUG
if (DEBUGL (5))
{
printf ("-");
}
#endif
termDelete (newterm);
return 0;
}
}
rd = runPointerGet (sys, run);
Termlist varlist = termlistAddVariables (NULL, rd->message);
fp.sys = sys;
fp.run = run;
fp.roledef = rd;
fp.proceed = proceed;
fp.solution = solution;
#ifdef DEBUG
if (DEBUGL (5))
{
indent ();
printf ("{\n");
}
#endif
flag = fixVariablelist (fp, sys->know, varlist, rd->message);
termlistDelete (varlist);
#ifdef DEBUG
if (DEBUGL (5))
{
indent ();
printf ("} with flag %i\n", flag);
}
#endif
return flag;
}
/*
* block
*
* Skips over an event. Because the intruder knowledge is incremental, we can
* just overwrite the old value of forbidden.
*/
int
block_basic (const System sys, const int run)
{
Knowledge pushKnow;
Roledef rd;
rd = runPointerGet (sys, run);
pushKnow = rd->forbidden;
rd->forbidden = sys->know;
traverse (sys);
rd->forbidden = pushKnow;
return 1;
}
int
send_basic (const System sys, const int run)
{
Roledef rd = runPointerGet (sys, run);
/* execute send, push knowledge? */
if (inKnowledge (sys->know, rd->message))
{
/* no new knowledge, so this remains */
explorify (sys, run);
}
else
{
/* new knowledge, must store old state */
Knowledge oldknow = sys->know;
sys->know = knowledgeDuplicate (sys->know);
sys->knowPhase++;
knowledgeAddTerm (sys->know, rd->message);
explorify (sys, run);
sys->knowPhase--;
knowledgeDelete (sys->know);
sys->know = oldknow;
}
return 1;
}

11
src/match_basic.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef MATCHBASIC
#define MATCHBASIC
int matchRead_basic (const System sys, const int run,
int (*proceed) (System, int));
int enabled_basic (const System sys, const Knowledge know,
const Term newterm);
int block_basic (const System sys, const int run);
int send_basic (const System sys, const int run);
#endif

502
src/match_clp.c Normal file
View File

@ -0,0 +1,502 @@
#include <stdlib.h>
#include <stdio.h>
#include "match_clp.h"
#include "runs.h"
#include "memory.h"
#include "constraints.h"
#include "mgu.h"
#include "memory.h"
#include "debug.h"
#include "match_clp.h"
#include "modelchecker.h"
struct solvepass
{
int (*solution) (struct solvepass, Constraintlist);
System sys;
int run;
int (*proceed) (System, int);
};
int
solve (const struct solvepass sp, Constraintlist solvecons)
{
Constraintlist activecl, cl, beforecl;
Constraint activeco;
int flag;
flag = 0;
/* locate first non-variable constraint */
activecl = firstNonVariable (solvecons);
if (activecl == NULL)
{
/* no such thing, so that's nice */
if (sp.solution != NULL)
sp.solution (sp, solvecons);
return 1;
}
/* there is an active constraint */
/* detach it from the list, but retain */
beforecl = activecl->prev;
solvecons = constraintlistUnlink (activecl);
activeco = activecl->constraint;
if (isTermTuple (activeco->term))
{
/* it's a tuple, so we unfold it first */
Constraintlist oldcl = solvecons;
cl = constraintlistDuplicate (solvecons);
cl =
constraintlistAdd (cl,
makeConstraint (deVar (activeco->term)->op1,
activeco->know));
cl =
constraintlistAdd (cl,
makeConstraint (deVar (activeco->term)->op2,
activeco->know));
solvecons = cl;
flag = solve (sp, solvecons) || flag;
constraintlistDestroy (solvecons);
solvecons = oldcl;
if (flag && sp.solution == NULL)
return 1;
}
else
{
/* not a tuple. does it unify? */
//TODO or remove: termNormalize(activeco->term);
void examine (Termlist tl)
{
Termlist tlres, tlscan;
int goodsubst;
while (tl != NULL)
{
//TODO or remove: termNormalize(tl->term);
tlres = termMguTerm (activeco->term, tl->term);
/* check whether this is a valid
* substitution */
goodsubst = 1;
tlscan = tlres;
while (tlscan != NULL && tlres != MGUFAIL)
{
if (validSubst (sp.sys->match, tlscan->term))
{
tlscan = tlscan->next;
}
else
{
goodsubst = 0;
tlscan = NULL;
}
}
if (tlres != MGUFAIL && goodsubst)
{
/* maybe this has modified current and previous knowledge! */
/* modify and copy _all_ knowledge instances, if needed, that is
all constraints as well as all agent knowledge! */
Constraintlist oldcl = NULL;
int copied = 0;
if (tlres != NULL)
{
copied = 1;
/* sometimes not needed, when no substitutions took place */
oldcl = solvecons;
solvecons = constraintlistDuplicate (solvecons);
Constraintlist cl = solvecons;
while (cl != NULL)
{
cl->constraint->know =
knowledgeSubstDo (cl->constraint->know);
cl = cl->next;
}
}
/* explore this new state */
flag = solve (sp, solvecons) || flag;
/* undo changes */
if (copied)
{
Constraintlist cl;
cl = solvecons;
while (cl != NULL)
{
knowledgeDelete (cl->constraint->know);
cl = cl->next;
}
constraintlistDestroy (solvecons);
solvecons = oldcl;
cl = solvecons;
while (cl != NULL)
{
knowledgeSubstUndo (cl->constraint->know);
cl = cl->next;
}
}
}
else
{
/* unification failed */
}
if (tlres != MGUFAIL)
{
tlscan = tlres;
while (tlscan != NULL)
{
tlscan->term->subst = NULL;
tlscan = tlscan->next;
}
termlistDelete (tlres);
}
/* abort if necessary */
if (flag && sp.solution == NULL)
return;
tl = tl->next;
}
}
examine (activeco->know->basic);
if (flag && sp.solution == NULL)
return 1;
examine (activeco->know->encrypt);
if (flag && sp.solution == NULL)
return 1;
if (isTermEncrypt (activecl->constraint->term))
{
/* shouldn't this be a branch? TODO */
Constraintlist oldcl = solvecons;
cl = constraintlistDuplicate (oldcl);
cl =
constraintlistAdd (cl,
makeConstraint (activeco->term->op,
activeco->know));
cl =
constraintlistAdd (cl,
makeConstraint (activeco->term->key,
activeco->know));
solvecons = cl;
flag = solve (sp, solvecons) || flag;
constraintlistDestroy (solvecons);
solvecons = oldcl;
if (flag && sp.solution == NULL)
return 1;
}
}
/* relink detached link */
if (beforecl == NULL)
{
solvecons = constraintlistConcat (activecl, solvecons);
}
else
{
activecl->prev = beforecl;
activecl->next = beforecl->next;
beforecl->next = activecl;
if (activecl->next != NULL)
activecl->next->prev = activecl;
}
return flag;
}
int
matchRead_clp (const System sys, const int run, int (*proceed) (System, int))
{
Constraintlist oldcl, newcl;
Constraint co;
Roledef runPoint;
int flag;
/* save old state */
oldcl = sys->constraints;
newcl = constraintlistShallow (oldcl);
/* creat new state */
runPoint = runPointerGet (sys, run);
/* we know this is a read */
co = makeConstraint (runPoint->message, sys->know);
newcl = constraintlistAdd (newcl, co);
sys->constraints = newcl;
#ifdef DEBUG
if (DEBUGL (5))
{
constraintlistPrint (newcl);
}
#endif
/* check solvability */
int solution (const struct solvepass sp, const Constraintlist cl)
{
Knowledge oldknow = NULL;
Constraintlist oldcl = sys->constraints;
int flag = 0;
int copied = 0;
sys->constraints = cl;
if (knowledgeSubstNeeded (sys->know))
{
copied = 1;
oldknow = sys->know;
sys->know = knowledgeSubstDo (sys->know);
}
flag = sp.proceed (sys, run);
if (copied)
{
knowledgeDelete (sys->know);
sys->know = oldknow;
knowledgeSubstUndo (sys->know);
}
sys->constraints = oldcl;
return flag;
}
struct solvepass sp;
sp.solution = solution;
sp.sys = sys;
sp.run = run;
sp.proceed = proceed;
flag = solve (sp, sys->constraints);
/* restore memory allocation */
constraintDestroy (co);
constraintlistDelete (newcl);
sys->constraints = oldcl;
return flag;
}
int
enabled_clp (const System sys, const int run)
{
return 1;
}
int
block_clp (const System sys, const int run)
{
return 1;
}
int
secret_clp (const System sys, const Term t)
{
Constraintlist oldcl, newcl;
Constraint co;
int flag;
/* save old state */
oldcl = sys->constraints;
newcl = constraintlistShallow (oldcl);
/* we know this is a read */
co = makeConstraint (t, sys->know);
newcl = constraintlistAdd (newcl, co);
sys->constraints = newcl;
/* check solvability */
struct solvepass sp;
sp.solution = NULL;
sp.sys = sys;
flag = !solve (sp, sys->constraints);
/* restore memory allocation */
constraintDestroy (co);
constraintlistDelete (newcl);
sys->constraints = oldcl;
return flag;
}
void
sendAdd_clp (const System sys, const int run, const Termlist tl)
{
Term t;
Termlist tl2;
if (tl == NULL)
{
/* TODO because the constraints might have changed, we can try to solve them again... */
explorify (sys, run);
return;
}
t = deVar (tl->term);
if (realTermLeaf (t))
{
/* leaf: simply add it */
knowledgeAddTerm (sys->know, t);
sendAdd_clp (sys, run, tl->next);
return;
}
else
{
/* node */
if (realTermTuple (t))
{
/* tuple */
tl2 = termlistShallow (tl->next);
tl2 = termlistAdd (tl2, t->op1);
tl2 = termlistAdd (tl2, t->op2);
sendAdd_clp (sys, run, tl2);
termlistDelete (tl2);
}
else
{
/* encrypt */
Term invkey;
invkey = inverseKey (sys->know->inverses, t->key);
if (!hasTermVariable (invkey))
{
/* simple case: no variable inside */
knowledgeAddTerm (sys->know, t);
tl2 = termlistShallow (tl->next);
if (inKnowledge (sys->know, invkey) && hasTermVariable (t->op))
tl2 = termlistAdd (tl2, t->op);
sendAdd_clp (sys, run, tl2);
termlistDelete (tl2);
}
else
{
/* difficult case: variable in inverse
* key. We have to branch. */
/* branch 1 : invkey not in knowledge */
/* TODO this yields a negative constraint, which we omit for the time being */
Knowledge oldknow = knowledgeDuplicate (sys->know);
knowledgeAddTerm (sys->know, t);
sendAdd_clp (sys, run, tl->next);
knowledgeDelete (sys->know);
sys->know = oldknow;
/* branch 2 : invkey in knowledge */
oldknow = knowledgeDuplicate (sys->know);
Constraintlist clold = sys->constraints;
Constraintlist clbuf = constraintlistShallow (clold);
tl2 = termlistShallow (tl->next);
Constraint co = makeConstraint (invkey, sys->know);
sys->constraints = constraintlistAdd (clbuf, co);
/* we _could_ explore first if this is solveable */
knowledgeAddTerm (sys->know, t);
tl2 = termlistAdd (tl2, t->op);
sendAdd_clp (sys, run, tl2);
termlistDelete (tl2);
constraintDestroy (co);
constraintlistDelete (clbuf);
sys->constraints = clold;
knowledgeDelete (sys->know);
sys->know = oldknow;
}
}
}
}
int
send_clp (const System sys, const int run)
{
Roledef rd = runPointerGet (sys, run);
/* execute send, push knowledge? */
if (inKnowledge (sys->know, rd->message))
{
/* no new knowledge, so this remains */
explorify (sys, run);
}
else
{
/* new knowledge, must store old state */
Knowledge oldknow;
oldknow = sys->know;
sys->know = knowledgeDuplicate (sys->know);
Termlist tl = termlistAdd (NULL, rd->message);
sendAdd_clp (sys, run, tl);
termlistDelete (tl);
knowledgeDelete (sys->know);
sys->know = oldknow;
}
return 1;
}
int
isPossible_clp (const System sys, const int run, int
(*proceed) (System, int), const Term t, const Knowledge k)
{
Constraintlist oldcl, newcl;
Constraint co;
Roledef runPoint;
int flag;
/* save old state */
oldcl = sys->constraints;
newcl = constraintlistShallow (oldcl);
/* creat new state */
runPoint = runPointerGet (sys, run);
/* add the new constraint */
co = makeConstraint (t, k);
newcl = constraintlistAdd (newcl, co);
sys->constraints = newcl;
/* check solvability */
int solution (const struct solvepass sp, const Constraintlist cl)
{
Knowledge oldknow = NULL;
Constraintlist oldcl = sys->constraints;
int flag = 0;
int copied = 0;
sys->constraints = cl;
if (knowledgeSubstNeeded (sys->know))
{
copied = 1;
oldknow = sys->know;
sys->know = knowledgeSubstDo (sys->know);
}
flag = sp.proceed (sys, run);
if (copied)
{
knowledgeDelete (sys->know);
sys->know = oldknow;
knowledgeSubstUndo (sys->know);
}
sys->constraints = oldcl;
return flag;
}
struct solvepass sp;
sp.solution = solution;
sp.sys = sys;
sp.run = run;
sp.proceed = proceed;
flag = solve (sp, sys->constraints);
/* restore memory allocation */
constraintDestroy (co);
constraintlistDelete (newcl);
sys->constraints = oldcl;
return flag;
}

13
src/match_clp.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef MATCHCLP
#define MATCHCLP
#include "runs.h"
int matchRead_clp (const System sys, const int run,
int (*proceed) (System, int));
int enabled_clp (const System sys, const int run);
int block_clp (const System sys, const int run);
int secret_clp (const System sys, const Term t);
int send_clp (const System sys, const int run);
#endif

48
src/memory.c Normal file
View File

@ -0,0 +1,48 @@
/* my own memory functions (not yet) */
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mcheck.h>
#include "memory.h"
#include "debug.h"
/* for displaying the sizes */
#include "terms.h"
#include "termlists.h"
#include "knowledge.h"
#include "substitutions.h"
#include "runs.h"
void
memInit ()
{
#ifdef DEBUG
if (DEBUGL (5))
{
void sp (char *txt, int size)
{
printf ("Size of %s : %i\n", txt, size);
}
printf ("Data structure size.\n\n");
sp ("pointer", sizeof (Term));
sp ("term node", sizeof (struct term));
sp ("termlist node", sizeof (struct termlist));
sp ("knowledge node", sizeof (struct knowledge));
sp ("substituition node", sizeof (struct substitution));
sp ("substlist node", sizeof (struct substitutionlist));
sp ("roledef node", sizeof (struct roledef));
sp ("system node", sizeof (struct system));
printf ("\n");
}
mtrace ();
#endif
return;
}
void
memDone (int sw)
{
return;
}

14
src/memory.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef MEMORY
#define MEMORY
#include "string.h"
#include "debug.h"
#include <malloc.h>
void memInit ();
void memDone ();
#define memAlloc(t) malloc(t)
#define memFree(p,t) free(p)
#define memRealloc(p,t) realloc(p,t);
#endif

151
src/mgu.c Normal file
View File

@ -0,0 +1,151 @@
#include <stdlib.h>
#include <stdio.h>
#include "terms.h"
#include "termlists.h"
#include "substitutions.h"
#include "mgu.h"
#include "memory.h"
/*
Most General Unifier
Unification etc.
New version yields a termlist with substituted variables, which can later be reset to NULL.
*/
void
termlistSubstReset (Termlist tl)
{
while (tl != NULL)
{
tl->term->subst = NULL;
tl = tl->next;
}
}
Termlist
termMguTerm (Term t1, Term t2)
{
/* added for speed */
t1 = deVar (t1);
t2 = deVar (t2);
if (t1 == t2)
return NULL;
#ifdef DEBUG
void showSubst (Term t)
{
if (!DEBUGL (5))
return;
indent ();
printf ("Substituting ");
termPrint (t);
printf (", typed ");
termlistPrint (t->stype);
printf ("->");
termlistPrint (t->subst->stype);
printf ("\n");
}
#endif
if (!(hasTermVariable (t1) || hasTermVariable (t2)))
{
if (isTermEqual (t1, t2))
{
return NULL;
}
else
{
return MGUFAIL;
}
}
/* symmetrical tests for single variable */
if (isTermVariable (t1))
{
if (termOccurs (t2, t1))
return MGUFAIL;
else
{
t1->subst = t2;
#ifdef DEBUG
showSubst (t1);
#endif
return termlistAdd (NULL, t1);
}
}
if (isTermVariable (t2))
{
if (termOccurs (t1, t2))
return MGUFAIL;
else
{
t2->subst = t1;
#ifdef DEBUG
showSubst (t2);
#endif
return termlistAdd (NULL, t2);
}
}
/* left & right are compounds with variables */
if (t1->type != t2->type)
return MGUFAIL;
/* identical compounds */
/* encryption first */
if (isTermEncrypt (t1))
{
Termlist tl1, tl2;
tl1 = termMguTerm (t1->key, t2->key);
if (tl1 == MGUFAIL)
{
return MGUFAIL;
}
else
{
tl2 = termMguTerm (t1->op, t2->op);
if (tl2 == MGUFAIL)
{
termlistSubstReset (tl1);
termlistDelete (tl1);
return MGUFAIL;
}
else
{
return termlistConcat (tl1, tl2);
}
}
}
/* tupling second
non-associative version ! TODO other version */
if (isTermTuple (t1))
{
Termlist tl1, tl2;
tl1 = termMguTerm (t1->op1, t2->op1);
if (tl1 == MGUFAIL)
{
return MGUFAIL;
}
else
{
tl2 = termMguTerm (t1->op2, t2->op2);
if (tl2 == MGUFAIL)
{
termlistSubstReset (tl1);
termlistDelete (tl1);
return MGUFAIL;
}
else
{
return termlistConcat (tl1, tl2);
}
}
}
return MGUFAIL;
}

12
src/mgu.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef MGU
#define MGU
#include "terms.h"
#include "termlists.h"
#include "substitutions.h"
#define MGUFAIL (Termlist) -1
Termlist termMguTerm (Term t1, Term t2);
#endif

1171
src/modelchecker.c Normal file

File diff suppressed because it is too large Load Diff

6
src/modelchecker.h Normal file
View File

@ -0,0 +1,6 @@
int traverse (const System oldsys);
int explorify (const System sys, const int run);
int executeStep (const System sys, const int run);
int propertyCheck (const System sys);
Termlist claimViolationDetails (const System sys, const int run, const Roledef
rd, const Knowledge know);

76
src/notes.txt Normal file
View File

@ -0,0 +1,76 @@
- best heuristic currently for -t8: ignore sendsfirst, just look at the
previous event and continue at that run.
- termPrint must currently be encapsulated in a math environment to work in
latex output, I wil change this later to some ensure mathmode construct,
probably with something like latexTermPrint.
- Repository to apache2 webdav.
- The trace incremental search should start at something like 'distance of
first claim + SOMECONST * runs'. SOMECONST relates to the partial-order
induced trace prolonings.
- For now, CLP is non-working and not checked. Reconsider this later.
- Because the properties checked are related to the partial order reductions,
it makes sense to check 'all secrecy claims' or 'all synchronisation claims'
at once.
- Once an attack is generated, we know the actual scenario and the trace
length. We might re-use this information to generate the shortest attack
using no partial order reduction. Note that choosing a wise method of
finding that is a mathematical issue: searching -t1 is exponential, so how
do we step trough these traces in order to find the shortest trace in the
quickest way? This can be determined under some (statistical) assumptions.
- The incremental check can be done much easier, by just retrying the main
loop explore with different parameters. It keeps everything nicely intact.
We must check for fails however, and how pruning is affected.
- Incremental check can at least be done in two ways: either by limiting the
number of runs (big axe method) or by limiting the trace length (nice).
There is a drawback to trace length only: the superfluous sends of the
algorithm in a scenario with many runs might interfere with the usefulness
of short traces. Maybe some heuristic that reduces the runs automatically is
required. (e.g. 'number of runs is at most MaxTraceLength/MaxRoleLength' or
something like that). Do analysis.
- If synch checking is expensive, introduce a limit (for -p0 stuff).
Basically, after the limit (if -p0 is set), we stop checking synch claims.
This then is default behaviour, to be overridden or changed by a switch.
- clp does not yet consider the matching for variables that have not been
instantiated. This *might* lead to some improvement, e.g. when there is only
one candidate for the variable. In general, I don't think it will help.
- match_clp.c 1.25 introduced the variable_in_invkey brancher, which hasn't
been thoroughly tested yet. Please do test.
- Brutus is slower than -t4. CLP is much, much faster however than both.
- It is very important to have variables in the run agent list, because it
dramatically decreases the complexity of the system, as opposed to just
creating runs for all possibilities. However, this explicitly introduces the
clp problem of var encryptions (see above).
- Given originator assumptions and such, we might want to implement the
compiler, that for non-typed matching, it will ignore all type definitions
in the code (as in, putting them in stype, but still considering Function).
Then, for 'any agent' we can use stype silently. The modelchecker should
then always consider the types with -m0 and -m1.
- In a paper concerning the CASRUL compiler, they mention associativity for
the equality relations. Note that CASRUL restricts the intruder actions,
and sometimes uses approximations.
- MS and CE never mention associativity as a restriction.
- For now, clp stuff will use pairing and simple mgu. Maybe a -m3 switch will
add the associative variant later.
- MALLOC_TRACE is the environment variable that triggers mtrace() output.
- Several memory leak detectors are still in place, they can all be located by
searching for "lead" or "diff" and destroying the code.
- knowledgeAddTerm might be improved by scanning through key list only with
things that are newly added.
- Associativity and unification don't play together well; consider other
algorithms. Maybe a simple explore (x,y),z and explore x,(y,z) will do, e.g.
take any split point for both sequences.
- POR (-t3) is actually worse than -t2: sends first. After some pondering I
now know why. It's because simultaneous reads yield traces in which there
are attacks that are also in the ones where we have R0S0S0;R1 (i.e. is thus
equivalent with R0;R1;S0S0)
- Knowledge is monotonous. So, if we say 'R#0' cannot be triggered by some
knowledge, we can just use a pointer for it. If we do want to trigger it, we
need to compare two knowledge pointers. As they don't have a unique
representation, it is more difficult. For now, I will just forbid specific
branches of the read when a message is in some previous knowledge, which is
more precise.
- Comparisons with Casper are in order.
- It is a good idea to have any number of input files, and parse them all, to
combine scenarios. A command should be "require <file>", because that would
enable scenarios to load the required role definitions. It's require instead
of include, because of possible multiple occurrences.

443
src/output.c Normal file
View File

@ -0,0 +1,443 @@
/*
* output.c
*
* Outputs an attack.
* Currently, every attack is printed.
* TODO move attacks to a buffer, and print _only_ the shortest one.
*/
#include <stdlib.h>
#include <stdio.h>
#include "runs.h"
#include "latex.h"
void linePrint(int i)
{
indent();
while (i > 0) {
printf("--------");
i--;
}
printf("\n");
}
int correspondingSend(System sys, int rd)
{
int labelMatch = 0;
int toMatch = 0;
int fromMatch = 0;
int tofromMatch = 0;
int messageMatch = 0;
int nMatches = 0;
int maxNMatches = 0;
int readEvent = rd;
int sendEvent = -1;
int bestSendEvent = -1;
for (sendEvent = readEvent; sendEvent >= 0; sendEvent--) {
if (sys->traceEvent[sendEvent]->type == SEND) {
/* do all the different kind of matchings first */
labelMatch =
isTermEqualFn(sys->traceEvent[sendEvent]->label,
sys->traceEvent[readEvent]->label);
toMatch =
isTermEqualFn(sys->traceEvent[sendEvent]->to,
sys->traceEvent[readEvent]->to);
fromMatch =
isTermEqualFn(sys->traceEvent[sendEvent]->from,
sys->traceEvent[readEvent]->from);
tofromMatch = toMatch || fromMatch;
messageMatch =
isTermEqualFn(sys->traceEvent[sendEvent]->message,
sys->traceEvent[readEvent]->message);
/* calculate the score */
nMatches = labelMatch + tofromMatch + messageMatch;
if (nMatches == 3) {
/* bingo! success on all matches */
//printf("Found perfect match: %d\n", s);
bestSendEvent = sendEvent;
break;
}
if (nMatches > maxNMatches) {
/* if we found a better candidate than we already had, we'll update */
//printf("Comparing SEND #%d: ",s);
//if (labelMatch) printf("label ");
//if (toMatch) printf("to ");
//if (fromMatch) printf("from ");
//if (messageMatch) printf("message ");
//printf("\n");
/* however, we first want to be sure that at least some matches are successful */
if (labelMatch && messageMatch) {
/* strongest restriction: message and label should match */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
} else if (messageMatch) {
/* if label AND message don't match: */
/* at least message should match */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
} else if (labelMatch) {
/* if message doesn't match */
/* the label should matches */
maxNMatches = nMatches;
bestSendEvent = sendEvent;
}
//printf("Best match: %d maxNMatches: %d\n", s, maxNMatches);
}
}
}
//bestSendEvent = NULL;
if (bestSendEvent == -1) {
/*Termlist tl;
Term t;
//newtl = knowledgeNew(sys->traceKnow[i],sys->traceKnow[i+1]);
for (tl = sys->traceKnow[rd]->basic; tl != NULL; tl = tl->next)
{
t = tl->term;
termPrint(t);
printf(" - ");
}
printf("\n");
for (tl = sys->traceKnow[rd]->encrypt; tl != NULL; tl = tl->next)
{
t = tl->term;
termPrint(t);
printf(" - ");
}
printf("\n");
for (tl = sys->traceKnow[rd]->inverses; tl != NULL; tl = tl->next)
{
t = tl->term;
termPrint(t);
printf(" - ");
}
printf("\n"); */
int u;
for (u = 0; u < rd; u++) {
if (sys->traceEvent[u]->type == SEND) {
//termPrint(readEvent->message);
//printf("\n");
knowledgePrint(sys->traceKnow[u]);
//printf("Is received message in knowledge after SEND %d? %d\n", u, inKnowledge(sys->traceKnow[u+1],readEvent->message));
if (inKnowledge
(sys->traceKnow[u + 1],
sys->traceEvent[readEvent]->message)) {
bestSendEvent = u;
break;
}
}
}
}
if (bestSendEvent == -1) {
printf("!! Could not find a matching SEND\n");
} else {
//latexMessagePrint(sys, bestSendEvent, readEvent);
//printf("Latex: ");
//termPrint(bestSendEvent->from);
//printf(" -> ");
if (!isTermEqualFn
(sys->traceEvent[bestSendEvent]->to,
sys->traceEvent[readEvent]->to)) {
//termPrint(bestSendEvent->to);
//printf(" -> ");
}
if (!isTermEqualFn
(sys->traceEvent[bestSendEvent]->from,
sys->traceEvent[readEvent]->from)) {
//termPrint(readEvent->from);
//printf(" -> ");
}
//termPrint(readEvent->to);
//printf("\n");
}
return bestSendEvent;
}
void tracePrint(System sys)
{
if (sys->latex) {
//latexTracePrint(sys);
return;
}
int i, j;
int lastrid;
int width;
Termlist newtl;
/* fix the 'next' knowledge, this is required because sometimes
* when calling this function, the next knowledge is not stored
* yet, but required for the general form of the output . */
sys->traceKnow[sys->step + 1] = sys->know;
/* how wide is the trace? */
width = 0;
for (i = 0; i <= sys->step; i++) {
if (sys->traceRun[i] >= width)
width = sys->traceRun[i] + 1;
}
linePrint(width);
indent();
printf("Dumping trace:\n");
linePrint(width);
/* first some parameter issues */
knowledgePrint(sys->traceKnow[0]);
/* also print inverses */
indent();
printf("Inverses: ");
knowledgeInversesPrint(sys->traceKnow[0]);
printf("\n");
/* Trace columns header. First the run identifier and role. On the
* second line we have the perceived agents for each partner role.
* These are printed in the same order as the role specification in the
* protocol. */
linePrint(width);
indent();
for (i = 0; i < width; i++) {
termPrint(sys->runs[i].role->nameterm);
printf("#%i\t", i);
}
printf("\n");
for (i = 0; i < width; i++) {
termPrint(agentOfRun(sys, i));
printf("\t");
}
printf("\n");
for (i = 0; i < width; i++) {
agentsOfRunPrint(sys, i);
printf("\t");
}
printf("\n");
/* now we print the actual trace */
void sticks(int i) {
while (i > 0) {
printf("|\t");
i--;
}
}
void sticksLine(void) {
sticks(width);
printf("\n");
}
linePrint(width);
lastrid = -1;
for (i = 0; i <= sys->step; i++) {
/* yields extra newlines between switching of runs */
j = sys->traceRun[i];
if (j != lastrid) {
sticksLine();
lastrid = j;
}
/* print the actual event */
indent();
sticks(j);
roledefPrint(sys->traceEvent[i]);
//if (sys->traceEvent[i]->type == READ && !sys->traceEvent[i]->internal)
//{
/* calls routine to find the best SEND-candidate */
/* the result is not yet being used */
// printf("\n");
// correspondingSend(sys, i);
//}
/* have we learnt anything new? */
newtl = knowledgeNew(sys->traceKnow[i], sys->traceKnow[i + 1]);
if (newtl != NULL) {
printf("\n");
sticksLine();
sticks(width);
printf("/* Intruder learns ");
termlistPrint(newtl);
termlistDelete(newtl);
printf(" */");
lastrid = -1;
}
/* new line */
printf("\n");
}
switch (sys->clp) {
case 1:
indent();
printf("---[ constraints ]-----\n");
constraintlistPrint(sys->constraints);
break;
default:
break;
}
linePrint(width);
}
void attackDisplayAscii(System sys)
{
int i, j;
int length;
int lastrid;
int width;
Termlist newtl;
struct tracebuf *tb;
/* attack trace buffer */
tb = sys->attack;
length = sys->attack->length;
/* set variables */
varbufSet (sys, tb->variables);
/* how wide is the trace? */
width = 0;
for (i = 0; i < length; i++) {
if (tb->run[i] >= width)
width = tb->run[i] + 1;
}
linePrint(width);
indent();
printf("Dumping trace:\n");
linePrint(width);
/* first some parameter issues */
knowledgePrint(tb->know[0]);
printf ("Variables: ");
termlistPrint (sys->variables);
printf ("\n");
/* Trace columns header. First the run identifier and role. On the
* second line we have the perceived agents for each partner role.
* These are printed in the same order as the role specification in the
* protocol. */
linePrint(width);
indent();
for (i = 0; i < width; i++) {
termPrint(sys->runs[i].role->nameterm);
printf("#%i\t", i);
}
printf("\n");
for (i = 0; i < width; i++) {
termPrint(agentOfRun(sys, i));
printf("\t");
}
printf("\n");
for (i = 0; i < width; i++) {
agentsOfRunPrint(sys, i);
printf("\t");
}
printf("\n");
/* now we print the actual trace */
void sticks(int i) {
while (i > 0) {
printf("|\t");
i--;
}
}
void sticksLine(void) {
sticks(width);
printf("\n");
}
linePrint(width);
lastrid = -1;
for (i = 0; i < length; i++) {
/* yields extra newlines between switching of runs */
j = tb->run[i];
if (j != lastrid) {
sticksLine();
lastrid = j;
}
/* print the actual event */
indent();
sticks(j);
roledefPrint(tb->event[i]);
//if (sys->traceEvent[i]->type == READ && !sys->traceEvent[i]->internal)
//{
/* calls routine to find the best SEND-candidate */
/* the result is not yet being used */
// printf("\n");
// correspondingSend(sys, i);
//}
/* have we learnt anything new? */
newtl = knowledgeNew(tb->know[i], tb->know[i + 1]);
if (newtl != NULL) {
printf("\n");
sticksLine();
sticks(width);
printf("/* Intruder learns ");
termlistPrint(newtl);
termlistDelete(newtl);
printf(" */");
lastrid = -1;
}
/* new line */
printf("\n");
}
linePrint(width);
}
void attackDisplay(System sys)
{
if (sys->latex) {
attackDisplayLatex(sys);
} else {
attackDisplayAscii(sys);
}
}

9
src/output.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef OUTPUT
#define OUTPUT
#include "runs.h"
void tracePrint(System sys);
void attackDisplay(System sys);
#endif

281
src/parser.y Normal file
View File

@ -0,0 +1,281 @@
%{
#include "pheading.h"
#include "scanner.c"
#include "tac.h"
struct tacnode* spdltac;
int yyerror(char *s);
int yylex(void);
%}
%union{
char* str;
struct tacnode* tac;
Symbol symb;
}
%token <symb> ID
%token PROTOCOL
%token ROLE
%token READT
%token SENDT
%token CLAIMT
%token VAR
%token CONST
%token RUN
%token SECRET
%token COMPROMISED
%token INVERSEKEYS
%token UNTRUSTED
%token USERTYPE
%type <tac> spdlcomplete
%type <tac> spdlrep
%type <tac> spdl
%type <tac> roles
%type <tac> role
%type <tac> roledef
%type <tac> event
%type <tac> declaration
%type <tac> secretpref
%type <tac> typeinfo1
%type <tac> typeinfoN
%type <tac> term
%type <tac> termlist
%type <tac> key
%type <tac> roleref
%type <symb> label
%start spdlcomplete
%%
spdlcomplete : spdlrep
{ spdltac = $1; }
;
spdlrep : /* empty */
{ $$ = NULL; }
| spdl spdlrep
{ $$ = tacCat($1,$2); }
;
spdl : UNTRUSTED termlist ';'
{
Tac t = tacCreate(TAC_UNTRUSTED);
t->tac1 = $2;
$$ = t;
}
| RUN roleref '(' termlist ')' ';'
{
Tac t = tacCreate(TAC_RUN);
t->tac1 = $2;
t->tac2 = $4;
$$ = t;
}
| PROTOCOL ID '(' termlist ')' '{' roles '}' optclosing
{
Tac t = tacCreate(TAC_PROTOCOL);
t->sym1 = $2;
t->tac2 = $7;
t->tac3 = $4;
$$ = t;
}
| USERTYPE termlist ';'
{
Tac t = tacCreate(TAC_USERTYPE);
t->tac1 = $2;
$$ = t;
}
| declaration
{
$$ = $1;
}
;
roles : /* empty */
{ $$ = NULL; }
| role roles
{ $$ = tacCat($1,$2); }
| declaration roles
{ $$ = tacCat($1,$2); }
;
role : ROLE ID '{' roledef '}' optclosing
{
Tac t = tacCreate(TAC_ROLE);
t->sym1 = $2;
t->tac2 = $4;
$$ = t;
}
;
optclosing : /* empty */
{ }
| ';'
{ }
;
roledef : /* empty */
{ $$ = NULL; }
| event roledef
{ $$ = tacCat($1,$2); }
| declaration roledef
{ $$ = tacCat($1,$2); }
;
event : READT label '(' termlist ')' ';'
{ Tac t = tacCreate(TAC_READ);
t->sym1 = $2;
/* TODO test here: tac2 should have at least 3 elements */
t->tac2 = $4;
$$ = t;
}
| SENDT label '(' termlist ')' ';'
{ Tac t = tacCreate(TAC_SEND);
t->sym1 = $2;
/* TODO test here: tac2 should have at least 3 elements */
t->tac2 = $4;
$$ = t;
}
| CLAIMT label '(' termlist ')' ';'
/* TODO maybe claims should be in the syntax */
{ Tac t = tacCreate(TAC_CLAIM);
t->sym1 = $2;
t->tac2 = $4;
$$ = t;
}
;
roleref : ID '.' ID
{ Tac t = tacCreate(TAC_ROLEREF);
t->sym1 = $1;
t->sym2 = $3;
$$ = t;
}
;
declaration : secretpref CONST termlist typeinfo1 ';'
{ Tac t = tacCreate(TAC_CONST);
t->tac1 = $3;
t->tac2 = $4;
t->tac3 = $1;
$$ = t;
}
| secretpref VAR termlist typeinfoN ';'
{ Tac t = tacCreate(TAC_VAR);
t->tac1 = $3;
t->tac2 = $4;
t->tac3 = $1;
$$ = t;
}
| SECRET termlist typeinfo1 ';'
{ Tac t = tacCreate(TAC_SECRET);
t->tac1 = $2;
t->tac2 = $3;
$$ = t;
}
| INVERSEKEYS '(' term ',' term ')' ';'
{ Tac t = tacCreate(TAC_INVERSEKEYS);
t->tac1 = $3;
t->tac2 = $5;
$$ = t;
}
| COMPROMISED termlist ';'
{ Tac t = tacCreate(TAC_COMPROMISED);
t->tac1= $2;
$$ = t;
}
;
secretpref : /* empty */
{
$$ = NULL;
}
| SECRET
{
Tac t = tacCreate(TAC_SECRET);
$$ = t;
}
;
typeinfo1 : /* empty */
{
Tac t = tacCreate(TAC_UNDEF);
$$ = t;
}
| ':' ID
{ Tac t = tacCreate(TAC_STRING);
t->sym1 = $2;
$$ = t;
}
;
typeinfoN : /* empty */
{
Tac t = tacCreate(TAC_UNDEF);
$$ = t;
}
| ':' termlist
{
$$ = $2;
}
;
label : /* empty */
{ $$ = NULL; }
| '_' ID
{ $$ = $2; }
;
term : ID
{
Tac t = tacCreate(TAC_STRING);
t->sym1 = $1;
$$ = t;
}
| ID '(' termlist ')'
{
Tac t = tacCreate(TAC_STRING);
t->sym1 = $1;
$$ = tacJoin(TAC_ENCRYPT,tacTuple($3),t,NULL);
}
| '{' termlist '}' key
{
$$ = tacJoin(TAC_ENCRYPT,tacTuple($2),$4,NULL);
}
| '(' termlist ')'
{
$$ = tacTuple($2);
}
;
termlist : term
{ }
| term ',' termlist
{ $$ = tacCat($1,$3); }
;
key : term
{ }
;
%%
// error handler routing
int yyerror(char *s)
{
extern int yylineno; // defined and maintained in lex.c
extern char *yytext; // defined and maintained in lex.c
printf("\nERROR %s at symbol %s on line %i.\n", s, yytext, yylineno);
exit(1);
}

13
src/pheading.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef PHEADING
#define PHEADING
#define YY_NO_UNPUT
#include <stdio.h>
#include <stdlib.h>
#include "terms.h"
#include "termlists.h"
#include "symbols.h"
#include "runs.h"
#include "tac.h"
#endif

33
src/releases.txt Normal file
View File

@ -0,0 +1,33 @@
? bonk
- New partial order reduction method.
Maybe CLP/t4
maybe MSC stuff
2004-02-19 billionaire
- replace substitutions with implicit substitutions.
- many syntax updates.
- many speed improvements.
2004-01-20 alpha1
teehee_valley with a couple of minor bugfixes.
- Shows error line correctly on parse.
- Allows for multi-line comments.
2004-01-20 teehee_valley
Nicely working role-based release, can test stdin scenario files.
- Preliminary untrusted support.
- Public, inversekeys are working.
- No tickets yet.
2004-01-19 amoxicillin
Preliminary compiler test release.
- Compiler works in ptest, now we can integrate it into the main
part, and throw out the scenarios.
2003 dead_ringers
A first working release.
- -t0 through -t2 implemented.
- Typed matching matches all basic terms.
- CLP matching works (-m2), but is not compatible with -t2.
- Hard coded protocols, inclusion through Makefile.

75
src/report.c Normal file
View File

@ -0,0 +1,75 @@
#include <stdio.h>
#include <stdlib.h>
#include "terms.h"
#include "runs.h"
#include "debug.h"
#include "output.h"
extern int globalLatex;
/* reportQuit is called after each violation, because it might need to abort the process */
void
reportQuit (System sys)
{
/* determine quit or not */
if (sys->prune >= 3)
{
indent ();
printf ("Quitting after %li claims, at the first violated claim.\n",
sys->claims);
sys->maxtracelength = 0;
}
}
void
reportStart (System sys)
{
if (!sys->latex)
{
indent ();
printf ("<REPORT>\n");
indent ();
}
statesPrint (sys);
}
void
reportMid (System sys)
{
indent ();
printf ("Trace length %i.\n", 1 + sys->step);
if (globalLatex)
printf("\n");
tracePrint (sys);
}
void
reportEnd (System sys)
{
if (!sys->latex)
{
indent ();
printf ("<REPORT>\n");
}
reportQuit (sys);
}
void
reportSecrecy (System sys, Term t)
{
if (!sys->report)
{
reportQuit (sys);
return;
}
reportStart (sys);
indent ();
printf ("Secrecy violation of $");
termPrint (t);
printf ("$\n");
if (globalLatex)
printf("\n");
reportMid (sys);
reportEnd (sys);
}

6
src/report.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef REPORT
#define REPORT
void reportSecrecy (System sys, Term t);
#endif

844
src/runs.c Normal file
View File

@ -0,0 +1,844 @@
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "terms.h"
#include "termlists.h"
#include "knowledge.h"
#include "runs.h"
#include "memory.h"
#include "constraints.h"
#include "debug.h"
#include "output.h"
#include "tracebuf.h"
/* from compiler.o */
extern Term TERM_Type;
/* for e.g. termprinting */
int globalLatex;
static int indentState = 0;
static int indentDepth = 0;
Run
makeRun ()
{
return (Run) memAlloc (sizeof (struct run));
}
Roledef
makeRoledef ()
{
return (Roledef) memAlloc (sizeof (struct roledef));
}
System
systemInit ()
{
System sys = (System) memAlloc (sizeof (struct system));
/* initially, no trace ofcourse */
sys->step = 0;
sys->shortestattack = INT_MAX;
sys->attack = tracebufInit();
/* switches */
sys->porparam = 0; // multi-purpose parameter
sys->latex = 0; // latex output?
/* set illegal traversal by default, to make sure it is set
later */
sys->traverse = 0;
sys->report = 1;
sys->switch_maxtracelength = INT_MAX;
sys->maxtracelength = INT_MAX;
/* init rundefs */
sys->maxruns = 0;
sys->runs = NULL;
/* no protocols yet */
sys->protocols = NULL;
sys->locals = NULL;
sys->variables = NULL;
sys->untrusted = NULL;
sys->secrets = NULL; // list of claimed secrets
sys->attack = NULL;
/* matching CLP */
sys->constraints = NULL; // no initial constraints
/* reset global counters */
systemReset (sys);
return sys;
}
void
systemReset (const System sys)
{
/* some initial counters */
sys->statesLow = 0; // number of explored states
sys->statesHigh = 0; // this is not as ridiculous as it might seem
sys->explore = 1; // do explore the space
sys->claims = 0; // number of claims encountered
sys->failed = 0; // number of failed claims
sys->knowPhase = 0; // knowledge transition id
termlistDestroy (sys->secrets); // remove old secrets list
sys->secrets = NULL; // list of claimed secrets
/* transfer switches */
sys->maxtracelength = sys->switch_maxtracelength;
/* POR init */
sys->PORphase = -1;
sys->PORdone = 1; // mark as 'something done' with previous reads
/* global latex switch: ugly, but otherwise I must carry it into every
* single subprocedure such as termPrint */
globalLatex = sys->latex;
}
void
systemDone (System sys)
{
int run;
int s;
/* clear globals, which were defined in systemStart */
s = sys->maxtracelength + 1;
memFree (sys->traceEvent, s * sizeof (Roledef));
memFree (sys->traceRun, s * sizeof (int));
memFree (sys->traceKnow, s * sizeof (Knowledge));
/* clear roledefs */
for (run = 0; run < sys->maxruns; run++)
roledefDestroy (runPointerGet (sys, run));
/* clear substructures */
termlistDestroy (sys->secrets);
/* clear main system */
systemDestroy (sys);
}
double
statesApproximation (System sys)
{
if (sys->statesHigh == 0)
return (double) sys->statesLow;
else
return (double) (sys->statesLow + (sys->statesHigh * ULONG_MAX));
}
void
statesPrintShort (System sys)
{
printf ("%.3e", statesApproximation (sys));
}
void
statesPrint (System sys)
{
if (sys->statesHigh == 0)
{
printf ("%g", (double) sys->statesLow);
}
else
{
double dstates;
dstates = sys->statesLow + (sys->statesHigh * ULONG_MAX);
printf ("%.3e (...)", dstates);
}
printf (" states traversed.\n");
if (globalLatex)
printf("\n");
}
void
systemDestroy (System sys)
{
memFree (sys->runs, sys->maxruns * sizeof (struct run));
memFree (sys, sizeof (struct system));
}
/* ensureValidRun
Makes sure memory is allocated for instantiating this run.
Note: This is meant to be used BEFORE using runPointerSet.
*/
void
ensureValidRun (System sys, int run)
{
int i, oldsize;
if (run < sys->maxruns)
return;
/* this amount of memory was not allocated yet */
/* (re)allocate space */
/* Note, this is never explicitly freed, because it is never
copied */
sys->runs = (Run) memRealloc (sys->runs, sizeof (struct run) * (run + 1));
/* update size parameter */
oldsize = sys->maxruns;
sys->maxruns = run + 1;
/* create runs, set the new pointer(s) to NULL */
for (i = oldsize; i < sys->maxruns; i++)
{
/* init run */
struct run myrun = sys->runs[i];
myrun.role = NULL;
myrun.agents = NULL;
myrun.index = NULL;
myrun.start = NULL;
myrun.know = knowledgeDuplicate (sys->know);
}
}
void
runAdd (System sys, int run, int type, Term label, Term from, Term to,
Term msg)
{
Roledef newEvent;
Roledef scan;
newEvent = roledefInit (type, label, from, to, msg);
ensureValidRun (sys, run);
if (runPointerGet (sys, run) == NULL)
{
sys->runs[run].start = newEvent;
runPointerSet (sys, run, newEvent);
}
else
{
scan = runPointerGet (sys, run);
while (scan->next != NULL)
scan = scan->next;
scan->next = newEvent;
}
}
void
roledefPrint (Roledef rd)
{
if (rd == NULL)
{
printf ("[Empty roledef]\n");
return;
}
if (rd->type == READ && rd->internal)
{
/* special case: internal read == choose ! */
printf ("CHOOSE(");
termPrint (rd->message);
printf (")");
return;
}
if (rd->type == READ)
printf ("READ");
if (rd->type == SEND)
printf ("SEND");
if (rd->type == CLAIM)
printf ("CLAIM");
if (rd->label != NULL)
{
if (globalLatex)
{
printf ("$_{");
termPrint (rd->label);
printf ("}$");
}
else
{
printf ("_");
termPrint (rd->label);
}
}
if (globalLatex)
printf ("$");
printf ("\t(");
termPrint (rd->from);
printf (",");
if (rd->type == CLAIM)
printf (" ");
termPrint (rd->to);
printf (", ");
termPrint (rd->message);
printf (" )");
if (globalLatex)
printf ("$");
}
void
runPrint (Roledef rd)
{
int i;
indent ();
i = 0;
while (rd != NULL)
{
printf ("%i: ", i);
roledefPrint (rd);
printf ("\n");
i++;
rd = rd->next;
}
}
void
runsPrint (System sys)
{
int i;
indent ();
printf ("[ Run definitions ]\n");
for (i = 0; i < (sys->maxruns); i++)
{
indent ();
printf ("Run definition %i:\n", i);
runPrint (runPointerGet (sys, i));
printf ("\n");
}
}
/*
* returns a pointer to the agent name term
*/
Term
agentOfRunRole (const System sys, const int run, const Term role)
{
Termlist roles = sys->runs[run].protocol->rolenames;
Termlist agents= sys->runs[run].agents;
/* TODO stupid reversed order, lose that soon */
agents = termlistForward(agents);
while (agents != NULL && roles != NULL)
{
if (isTermEqual(roles->term, role))
{
return agents->term;
}
agents = agents->prev;
roles = roles->next;
}
return NULL;
}
/*
* returns a pointer to the agent name term
*/
Term
agentOfRun (const System sys, const int run)
{
return agentOfRunRole(sys,run,sys->runs[run].role->nameterm);
}
Roledef
roledefDuplicate1 (const Roledef rd)
{
if (rd == NULL)
return NULL;
Roledef newrd = makeRoledef ();
memcpy (newrd, rd, sizeof (struct roledef));
newrd->next = NULL;
return newrd;
}
Roledef
roledefDuplicate (Roledef rd)
{
if (rd == NULL)
return NULL;
Roledef newrd = roledefDuplicate1 (rd);
newrd->next = roledefDuplicate (rd->next);
return newrd;
}
void
roledefDelete (Roledef rd)
{
if (rd == NULL)
return;
roledefDelete (rd->next);
memFree (rd, sizeof (struct roledef));
return;
}
void
roledefDestroy (Roledef rd)
{
if (rd == NULL)
return;
roledefDestroy (rd->next);
termDelete (rd->from);
termDelete (rd->to);
termDelete (rd->message);
memFree (rd, sizeof (struct roledef));
return;
}
/*
Instantiate a role by making a new run.
This involves creation of a new run(id).
Copy & subst of Roledef, Agent knowledge.
Tolist might contain type constants.
*/
void
roleInstance (const System sys, const Protocol protocol, const Role role,
const Termlist paramlist)
{
int rid;
Run runs;
Roledef rd;
Termlist scanfrom, scanto;
Termlist fromlist = NULL;
Termlist tolist = NULL;
Term extterm = NULL;
/* claim runid, allocate space */
rid = sys->maxruns;
ensureValidRun (sys, rid);
runs = sys->runs;
/* duplicate roledef in buffer rd */
rd = roledefDuplicate (role->roledef);
/* scan for types in agent list */
/* scanners */
scanfrom = protocol->rolenames;
scanto = paramlist;
while (scanfrom != NULL && scanto != NULL)
{
fromlist = termlistAdd (fromlist, scanfrom->term);
if (scanto->term->stype != NULL &&
inTermlist (scanto->term->stype, TERM_Type))
{
/* There is a TYPE constant in the parameter list.
* Generate a new local variable for this run, with this type */
Term newvar = makeTermType (VARIABLE, scanfrom->term->symb, rid);
sys->variables = termlistAdd (sys->variables, newvar);
newvar->stype = termlistAdd (NULL, scanto->term);
tolist = termlistAdd (tolist, newvar);
/* newvar is apparently new, but it might occur
* in the first event if it's a read, in which
* case we forget it */
if (!(rd->type == READ && termOccurs (rd->message, scanfrom->term)))
{
/* but this is already set in the first
* read... */
/* TODO scan might be more complex, but
* this will do for now. I.e. occurring
* first in a read will do */
extterm = makeTermTuple (newvar, extterm);
}
}
else
{
/* not a type constant, add to list */
tolist = termlistAdd (tolist, scanto->term);
}
scanfrom = scanfrom->next;
scanto = scanto->next;
}
/* prefix a read for such reads. TODO: this should also cover any external stuff */
if (extterm != NULL)
{
Roledef rdnew;
rdnew = roledefInit (READ, NULL, NULL, NULL, extterm);
/* this is an internal action! */
rdnew->internal = 1;
rdnew->next = rd;
rd = rdnew;
}
/* set parameters */
runs[rid].protocol = protocol;
runs[rid].role = role;
runs[rid].agents = termlistDuplicate (tolist);
runs[rid].start = rd;
runs[rid].index = rd;
/* duplicate all locals form this run */
scanto = role->locals;
while (scanto != NULL)
{
Term t = scanto->term;
if (!inTermlist (fromlist, t))
{
if (realTermLeaf (t))
{
Term newt = makeTermType (t->type, t->symb, rid);
if (realTermVariable (newt))
{
sys->variables = termlistAdd (sys->variables, newt);
}
newt->stype = t->stype;
fromlist = termlistAdd (fromlist, t);
tolist = termlistAdd (tolist, newt);
}
}
scanto = scanto->next;
}
/* TODO this is not what we want yet, also local knowledge. The local
* knowledge (list?) also needs to be substituted on invocation. */
runs[rid].know = knowledgeDuplicate (sys->know);
/* now adjust the local run copy */
rd = runs[rid].start;
while (rd != NULL)
{
rd->from = termLocal (rd->from, fromlist, tolist, role->locals, rid);
rd->to = termLocal (rd->to, fromlist, tolist, role->locals, rid);
rd->message =
termLocal (rd->message, fromlist, tolist, role->locals, rid);
rd = rd->next;
}
termlistDelete (fromlist);
termlistDelete (tolist);
}
Roledef
roledefInit (int type, Term label, Term from, Term to, Term msg)
{
Roledef newEvent;
newEvent = makeRoledef ();
newEvent->internal = 0;
newEvent->type = type;
newEvent->label = label;
newEvent->from = from;
newEvent->to = to;
newEvent->message = msg;
newEvent->forbidden = NULL; // no forbidden stuff
newEvent->knowPhase = -1; // we haven't explored any knowledge yet
newEvent->next = NULL;
return newEvent;
}
Roledef
roledefAdd (Roledef rd, int type, Term label, Term from, Term to, Term msg)
{
Roledef scan;
if (rd == NULL)
return roledefInit (type, label, from, to, msg);
scan = rd;
while (scan->next != NULL)
scan = scan->next;
scan->next = roledefInit (type, label, from, to, msg);
return rd;
}
/* allocate memory for traces, runs have to be known for that */
void
systemStart (System sys)
{
int i, s;
Roledef rd;
s = 0;
for (i = 0; i < sys->maxruns; i++)
{
rd = runPointerGet (sys, i);
while (rd != NULL)
{
s++;
rd = rd->next;
}
}
/* this is the maximum trace length */
if (sys->maxtracelength > s)
sys->maxtracelength = s;
/* trace gets one added entry for buffer */
s = sys->maxtracelength + 1;
/* freed in systemDone */
sys->traceEvent = memAlloc (s * sizeof (Roledef));
sys->traceRun = memAlloc (s * sizeof (int));
sys->traceKnow = memAlloc (s * sizeof (Knowledge));
/* clear, for niceties */
for (i = 0; i < s; i++)
{
sys->traceEvent[i] = NULL;
sys->traceRun[i] = 0;
sys->traceKnow[i] = NULL;
}
}
void
indentActivate ()
{
indentState = 1;
}
void
indentSet (int i)
{
if (indentState)
indentDepth = i;
}
void
indent ()
{
int i = indentDepth;
int j = 0;
while (i > 0)
{
printf ("%i ", j);
i--;
j++;
}
}
Protocol
protocolCreate (Term name)
{
Protocol p;
p = memAlloc (sizeof (struct protocol));
p->nameterm = name;
p->rolenames = NULL;
p->next = NULL;
p->roles = NULL;
p->locals = NULL;
return p;
}
Role
roleCreate (Term name)
{
Role r;
r = memAlloc (sizeof (struct role));
r->nameterm = name;
r->next = NULL;
r->locals = NULL;
r->roledef = NULL;
return r;
}
void
locVarPrint (Termlist tl)
{
if (tl == NULL)
{
printf ("No local terms.\n");
}
else
{
printf ("Local terms: ");
printf ("[");
while (tl != NULL)
{
termPrint (tl->term);
if (tl->term->stype != NULL)
{
printf (":");
termlistPrint (tl->term->stype);
}
tl = tl->next;
if (tl != NULL)
printf (",");
}
printf ("]");
printf ("\n");
}
}
void
protocolPrint (Protocol p)
{
if (p == NULL)
return;
indent ();
printf ("[[Protocol : ");
termPrint (p->nameterm);
printf (" (");
termlistPrint (p->rolenames);
printf (")]]\n");
locVarPrint (p->locals);
rolesPrint (p->roles);
}
void
protocolsPrint (Protocol p)
{
while (p != NULL)
{
protocolPrint (p);
p = p->next;
}
}
void
rolePrint (Role r)
{
if (r == NULL)
return;
indent ();
printf ("[[Role : ");
termPrint (r->nameterm);
printf ("]]\n");
locVarPrint (r->locals);
Roledef rd = r->roledef;
while (rd != NULL)
{
roledefPrint (rd);
printf ("\n");
rd = rd->next;
}
}
void
rolesPrint (Role r)
{
if (r == NULL)
{
printf ("Empty role.");
}
else
{
while (r != NULL)
{
rolePrint (r);
r = r->next;
}
}
}
int
untrustedAgent (System sys, Termlist agents)
{
while (agents != NULL)
{
if (isTermVariable (agents->term))
{
if (sys->clp)
{
/* clp: variables are difficult */
/* TODO Add as constraint that they're
* trusted */
/* However, that is a branch as well :(
*/
/* claim secret is _really_ a instant-multiple
* read. If it is succesful, we sound
* the alert */
}
}
else
{
if (inTermlist (sys->untrusted, agents->term))
return 1;
}
agents = agents->next;
}
return 0;
}
int
getMaxTraceLength (const System sys)
{
Roledef rd;
int maxlen;
int run;
maxlen = 0;
for (run = 0; run < sys->maxruns; run++)
{
rd = runPointerGet (sys, run);
while (rd != NULL)
{
rd = rd->next;
maxlen++;
}
}
return maxlen;
}
/*
* Nicely format the role and agents we think we're talking to.
*/
void
agentsOfRunPrint (const System sys, const int run)
{
Term role = sys->runs[run].role->nameterm;
Termlist roles = sys->runs[run].protocol->rolenames;
termPrint(role);
printf("(");
while (roles != NULL)
{
termPrint(agentOfRunRole(sys,run,roles->term));
roles = roles->next;
if (roles != NULL)
{
printf(",");
}
}
printf(")");
}
/*
* explain a violated claim at point i in the trace
*/
void
violatedClaimPrint (const System sys, const int i)
{
printf("Claim stuk");
}
/*
* attackLength yields the real (user friendly) length of an attack by omitting
* the redundant events but also the choose events.
*/
int attackLength(struct tracebuf* tb)
{
int len,i;
len = 0;
i = 0;
while (i < tb->length)
{
if (tb->status[i] != S_RED)
{
/* apparently not redundant */
if (!(tb->event[i]->type == READ && tb->event[i]->internal))
{
/* and no internal read, so it counts */
len++;
}
}
i++;
}
return len;
}

200
src/runs.h Normal file
View File

@ -0,0 +1,200 @@
#ifndef RUNS
#define RUNS
#include "terms.h"
#include "termlists.h"
#include "knowledge.h"
#include "constraints.h"
#define READ 1
#define SEND 2
#define CLAIM 3
#define runPointerGet(sys,run) sys->runs[run].index
#define runPointerSet(sys,run,newp) sys->runs[run].index = newp
struct roledef
{
/* flag for internal actions (overriding normal type) */
int internal;
int type;
Term label;
Term from;
Term to;
Term message;
struct roledef *next;
/* illegal injections */
Knowledge forbidden;
/* knowledge transitions counter */
int knowPhase;
/* evt runid for synchronisation, but that is implied in the
base array */
};
typedef struct roledef *Roledef;
struct role
{
Term nameterm;
Roledef roledef;
Termlist locals;
struct role *next;
};
typedef struct role *Role;
struct protocol
{
Term nameterm;
Role roles;
Termlist rolenames;
Termlist locals;
struct protocol *next;
};
typedef struct protocol *Protocol;
struct run
{
Protocol protocol;
Role role;
Termlist agents;
Roledef index;
Roledef start;
Knowledge know;
};
typedef struct run *Run;
struct varbuf
{
Termlist from;
Termlist to;
Termlist empty;
};
typedef struct varbuf *Varbuf;
struct tracebuf
{
int length;
int reallength;
Roledef *event;
int *run;
int *status;
int *link;
int violatedclaim; // index of violated claim in trace
Knowledge *know;
Termlist requiredterms;
Varbuf variables;
};
struct system
{
int step; // can be managed globally
Knowledge know;
struct parameters *parameters; // misc
/* static run info, maxruns */
Run runs;
/* global */
int maxruns;
/* properties */
Termlist secrets; // integrate secrets list into system
int shortestattack; // length of shortest attack trace
/* switches */
int report;
int prune; // type of pruning
int switch_maxtracelength; // helps to remember the length of the last trace
int maxtracelength; // helps to remember the length of the last trace
int switchM; // memory
int switchT; // time
int switchS; // progress (traversed states)
int porparam; // a multi-purpose integer parameter, passed to the partial order reduction method selected
int latex; // latex output switch
/* traversal */
int traverse; // traversal method
int explore; // boolean: explore states after actions or not
/* counters */
unsigned long int statesLow;
unsigned long int statesHigh;
unsigned long int claims; // number of claims encountered
unsigned long int failed; // number of claims failed
/* matching */
int match; // matching type
int clp; // do we use clp?
/* protocol definition */
Protocol protocols;
Termlist locals;
Termlist variables;
Termlist untrusted;
/* constructed trace pointers, static */
Roledef *traceEvent; // MaxRuns * maxRoledef
int *traceRun; // MaxRuns * maxRoledef
Knowledge *traceKnow; // Maxruns * maxRoledef
/* POR reduction assistance */
int PORphase; // -1: init (all sends), 0...: recurse reads
int PORdone; // simple bit to denote something was done.
int knowPhase; // which knowPhase have we already explored?
Constraintlist constraints; // only needed for CLP match
/* relevant: storage of shortest attack */
struct tracebuf* attack;
};
typedef struct system *System;
System systemInit ();
void systemReset (const System sys);
System systemDuplicate (System fromsys);
void statesPrint (System sys);
void statesPrintShort (System sys);
void systemDestroy (System sys);
void systemDone (System sys);
void ensureValidRun (System sys, int run);
void runAdd (System sys, int run, int type, Term label, Term from, Term to,
Term msg);
void roledefPrint (Roledef rd);
void runPrint (Roledef rd);
void runsPrint (System sys);
Term agentOfRunRole (const System sys, const int run, const Term role);
Term agentOfRun (const System sys, const int run);
Roledef roledefDuplicate1 (const Roledef rd);
Roledef roledefDuplicate (Roledef rd);
void roledefDelete (Roledef rd);
void roledefDestroy (Roledef rd);
void roleInstance (const System sys, const Protocol protocol, const Role role,
const Termlist tolist);
Roledef roledefInit (int type, Term label, Term from, Term to, Term msg);
Roledef roledefAdd (Roledef rd, int type, Term label, Term from, Term to,
Term msg);
void systemStart (System sys);
void indentActivate ();
void indentSet (int i);
void indent ();
Protocol protocolCreate (Term nameterm);
Role roleCreate (Term nameterm);
void locVarPrint (Termlist tl);
void protocolPrint (Protocol p);
void protocolsPrint (Protocol p);
void rolePrint (Role r);
void rolesPrint (Role r);
int untrustedAgent (System sys, Termlist agents);
int getMaxTraceLength (const System sys);
void agentsOfRunPrint (const System sys, const int run);
void violatedClaimPrint (const System sys, int i);
int attackLength(struct tracebuf* tb);
#endif

160
src/scanner.lex Normal file
View File

@ -0,0 +1,160 @@
%option yylineno
%{
/* scanner for security protocols language */
#include <strings.h>
#include "pheading.h"
#include "memory.h"
#include "tac.h"
/* tokens for language */
#include "tok.h"
void mkname(char *name);
void mkval(void);
void mktext(void);
int yyerror(char *s);
Symbol mkstring(char *name);
struct stringlist {
char* string;
struct stringlist* next;
};
typedef struct stringlist* Stringlist;
static Stringlist allocatedStrings = NULL;
int mylineno = 0;
%}
comment1 "//".*
comment2 "#".*
delimiter [ \t\n]
whitespace {delimiter}+
uc_letter [A-Z]
lc_letter [a-z]
letter {lc_letter}|{uc_letter}
digit [0-9]
ascii_char [^\"\n]
escaped_char \\n|\\\"
integer {digit}+
text \"({ascii_char}|{escaped_char})*\"
id ({letter}|{digit})+
%%
"/*" {
register int c;
for ( ; ; )
{
while ( (c = input()) != '*' && c != '\n' && c != EOF )
; /* eat up text of comment */
if ( c == '*' )
{
while ( (c = input()) == '*' )
;
if ( c == '/' )
break; /* found the end */
}
if (c == '\n')
mylineno++;
if ( c == EOF )
{
yyerror( "EOF in comment" );
break;
}
}
}
\n { mylineno++; }
{whitespace} { }
{comment1} { }
{comment2} { }
protocol { return PROTOCOL; }
role { return ROLE; }
read { return READT; }
send { return SENDT; }
var { return VAR; }
const { return CONST; }
claim { return CLAIMT; }
run { return RUN; }
secret { return SECRET; }
inversekeys { return INVERSEKEYS; }
untrusted { return UNTRUSTED; }
compromised { return COMPROMISED; }
usertype { return USERTYPE; }
{id} {
yylval.symb = mkstring(yytext);
return ID;
}
. { return yytext[0]; }
%%
Symbol mkstring(char *name)
{
Symbol t;
char* s;
Stringlist sl;
int len;
if (( t = lookup(name)) != NULL)
{
return t;
}
// make new name
len = strlen(name);
s = (char *)memAlloc(len+1);
sl = (Stringlist) memAlloc(sizeof(struct stringlist));
strncpy(s,name,len);
sl->next = allocatedStrings;
allocatedStrings = sl;
sl->string = s;
s[len] = EOS;
t = get_symb();
t->lineno = yylineno;
t->type = T_UNDEF;
t->text = s;
insert(t);
return t;
}
void scanner_cleanup(void)
{
yy_delete_buffer (YY_CURRENT_BUFFER);
}
void strings_cleanup(void)
{
Stringlist sl;
while (allocatedStrings != NULL)
{
sl = allocatedStrings;
allocatedStrings = sl->next;
memFree(sl->string, strlen(sl->string)+1);
memFree(sl, sizeof(struct stringlist));
}
}
/*
void mkval(void);
void mktext(void);
*/
// vim:ft=lex:

3
src/speedtest Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
./scyther -d -p0 -r 8 $* <spdl/speedtest.spdl

285
src/substitutions.c Normal file
View File

@ -0,0 +1,285 @@
#include <stdlib.h>
#include <stdio.h>
#include "terms.h"
#include "substitutions.h"
#include "memory.h"
/* substitutions in terms */
Substitution
makeSubstitution (Term from, Term to)
{
Substitution subs;
subs = memAlloc (sizeof (struct substitution));
subs->from = from;
subs->to = to;
return subs;
}
void
substitutionDelete (Substitution subs)
{
if (subs == NULL)
return;
memFree (subs, sizeof (struct substitution));
}
void
substitutionDestroy (Substitution subs)
{
if (subs == NULL)
return;
termDelete (subs->from);
termDelete (subs->to);
memFree (subs, sizeof (struct substitution));
}
/*
termSubstitute
Yields a new (deep copy) term of a term, according to the
substitution.
To remove the old term, use termDelete.
Be sure to use termNormalize on it afterwards!!
*/
Term
termSubstitute (Term term, Substitution subs)
{
if (term == NULL)
return NULL;
if (isTermEqual (term, subs->from))
{
return termDuplicate (subs->to);
}
else
{
if (!isTermLeaf (term))
{
if (isTermEncrypt (term))
{
return makeTermEncrypt (termSubstitute (term->op, subs),
termSubstitute (term->key, subs));
}
else
{
return
makeTermTuple (termSubstitute (term->op1, subs),
termSubstitute (term->op2, subs));
}
}
else
{
return termDuplicate (term);
}
}
}
/*
termlistSubstitute.
Makes a new list, deep copies of the terms.
To remove the old termlist, use termlistDestroy
TODO
*/
Termlist
termlistSubstitute (Termlist tl, Substitution subs)
{
if (tl == NULL)
return NULL;
else
{
Termlist tls = termlistSubstitute (tl->next, subs);
//return termlistAdd(termlistSubstitute(tl->next, subs),
// termSubstitute(tl->term, subs));
return tls;
}
}
void
substitutionPrint (Term t, Substitution subs)
{
printf ("Substituting ");
termPrint (subs->from);
printf (" by ");
termPrint (subs->to);
printf (" in ");
termPrint (t);
printf ("\n");
}
/* termSubstituteList
Not very efficient at the moment. Recursing through the term might be
a lot easier. However, this works.
*/
Term
termSubstituteList (Term term, Substitutionlist sl)
{
Term newt;
Term oldt;
if (sl == NULL)
return termDuplicate (term);
if (term == NULL)
return NULL;
newt = termSubstitute (term, sl->subst);
sl = sl->next;
while (sl != NULL)
{
oldt = newt;
newt = termSubstitute (oldt, sl->subst);
termDelete (oldt);
sl = sl->next;
}
return newt;
}
Substitutionlist
makeSubstitutionList (Substitution subs)
{
Substitutionlist sl;
sl = memAlloc (sizeof (struct substitutionlist));
sl->subst = subs;
sl->next = NULL;
return sl;
}
Substitutionlist
substitutionlistAdd (Substitutionlist sl, Term from, Term to)
{
return substitutionlistConcat (sl,
makeSubstitutionList (makeSubstitution
(from, to)));
}
void
substitutionlistDestroy (Substitutionlist sl)
{
if (sl != NULL)
{
substitutionDelete (sl->subst);
substitutionlistDestroy (sl->next);
memFree (sl, sizeof (struct substitutionlist));
}
}
void
substitutionlistAnnihilate (Substitutionlist sl)
{
if (sl != NULL)
{
substitutionDestroy (sl->subst);
substitutionlistDestroy (sl->next);
memFree (sl, sizeof (struct substitutionlist));
}
}
Substitutionlist
substitutionlistConcat (Substitutionlist sl1, Substitutionlist sl2)
{
Substitutionlist scan;
if (sl1 == NULL)
return sl2;
scan = sl1;
while (scan->next != NULL)
scan = scan->next;
scan->next = sl2;
return sl1;
}
/* substitute over termlist */
Termlist
substitutionBatch (Termlist tl, Substitutionlist sl)
{
if (tl == NULL)
return NULL;
if (sl == NULL)
return termlistDuplicate (tl);
Termlist newtl = NULL;
while (tl != NULL)
{
newtl = termlistAdd (newtl, termSubstituteList (tl->term, sl));
tl = tl->next;
}
return newtl;
}
/* substitute over roledef */
Roledef
substitutionRoledef (Roledef rdorig, Substitutionlist sl)
{
Roledef rd, rdscan;
rd = roledefDuplicate (rdorig);
rdscan = rd;
while (rdscan != NULL)
{
rdscan->from = termSubstituteList (rdscan->from, sl);
rdscan->to = termSubstituteList (rdscan->to, sl);
rdscan->message = termSubstituteList (rdscan->message, sl);
rdscan = rdscan->next;
}
return rd;
}
/* substitute over knowledge structure */
Knowledge
substitutionKnowledge (Knowledge know, Substitutionlist sl)
{
/* TODO this is wrong anyway, because it does not respect the knowledge invariants. We should remove the variables occurring on
the left, and add to the knowledge the new stuff */
Termlist repres, repres2;
Knowledge know2 = emptyKnowledge ();
knowledgeSetInverses (know2, knowledgeGetInverses (know));
repres = knowledgeSet (know);
repres2 = substitutionBatch (repres, sl);
knowledgeAddTermlist (know2, repres2);
termlistDelete (repres2);
termlistDelete (repres);
return know2;
}
void
substitutionlistPrint (Substitutionlist sl)
{
int i = 1;
if (sl == NULL)
printf ("[empty substitutionlist]\n");
else
{
while (sl != NULL)
{
printf ("%i: ", i);
termPrint (sl->subst->from);
printf (" -> ");
termPrint (sl->subst->to);
printf ("\n");
i++;
sl = sl->next;
}
}
}

44
src/substitutions.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef SUBSTITUTIONS
#define SUBSTITUTIONS
#include "termlists.h"
#include "knowledge.h"
#include "runs.h"
struct substitution
{
Term from;
Term to;
};
typedef struct substitution *Substitution;
struct substitutionlist
{
Substitution subst;
struct substitutionlist *next;
};
typedef struct substitutionlist *Substitutionlist;
Substitution makeSubstitution (Term from, Term to);
void substitutionDelete (Substitution subs);
void substitutionDestroy (Substitution subs);
Term termSubstitute (Term term, Substitution subs);
Termlist termlistSubstitute (Termlist tl, Substitution subs);
void substitutionPrint (Term t, Substitution subs);
Term termSubstituteList (Term term, Substitutionlist sl);
Substitutionlist makeSubstitutionList (Substitution subs);
Substitutionlist substitutionlistAdd (Substitutionlist sl, Term from,
Term to);
void substitutionlistDestroy (Substitutionlist sl);
void substitutionlistAnnihilate (Substitutionlist sl);
Substitutionlist substitutionlistConcat (Substitutionlist sl1,
Substitutionlist sl2);
Termlist substitutionBatch (Termlist tl, Substitutionlist sl);
Roledef substitutionRoledef (Roledef rd, Substitutionlist sl);
Knowledge substitutionKnowledge (Knowledge know, Substitutionlist sl);
void substitutionlistPrint (Substitutionlist sl);
#endif

145
src/symbols.c Normal file
View File

@ -0,0 +1,145 @@
#include <stdio.h>
#include <stdlib.h>
#include "symbols.h"
#include "memory.h"
/*
Symbol processor.
Stores symbols for the lexical scanner. Can later print them.
Implementation uses a hashtable, the size of which is defined in
symbols.h.
*/
extern int yylineno;
/* global declarations */
Symbol symbtab[HASHSIZE];
Symbol symb_list;
Symbol symb_alloc;
/* main code */
void
symbolsInit (void)
{
int i;
for (i = 0; i < HASHSIZE; i++)
symbtab[i] = NULL;
symb_list = NULL;
symb_alloc = NULL;
}
void
symbolsDone (void)
{
Symbol s;
while (symb_alloc != NULL)
{
s = symb_alloc;
symb_alloc = s->allocnext;
memFree (s, sizeof (struct symbol));
}
}
Symbol
get_symb (void)
{
Symbol t;
if (symb_list != NULL)
{
t = symb_list;
symb_list = symb_list->next;
}
else
{
t = (Symbol) memAlloc (sizeof (struct symbol));
t->allocnext = symb_alloc;
symb_alloc = t;
}
return t;
}
void
free_symb (Symbol s)
{
if (s == NULL)
return;
s->next = symb_list;
symb_list = s;
}
int
hash (char *s)
{
int hv = 0;
int i;
for (i = 0; s[i] != EOS; i++)
{
int v = (hv >> 28) ^ (s[i] & 0xf);
hv = (hv << 4) | v;
}
hv = hv & 0x7fffffff;
return hv % HASHSIZE;
}
void
insert (Symbol s)
{
if (s == NULL)
return; /* illegal insertion of empty stuff */
int hv = hash (s->text);
s->next = symbtab[hv];
symbtab[hv] = s;
}
Symbol
lookup (char *s)
{
if (s == NULL)
return NULL;
int hv = hash (s);
Symbol t = symbtab[hv];
while (t != NULL)
{
if (strcmp (t->text, s) == 0)
break;
else
t = t->next;
}
return t;
}
void
symbolPrint (Symbol s)
{
if (s == NULL)
return;
/* TODO maybe action depending on type? */
printf ("%s", s->text);
}
Symbol
symbolSysConst (char *str)
{
Symbol symb;
symb = lookup (str);
if (symb == NULL)
{
symb = get_symb ();
symb->lineno = yylineno;
symb->type = T_SYSCONST;
symb->text = str;
}
return symb;
}

37
src/symbols.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef SYMBOLS
#define SYMBOLS
/* Size of hashtable: optimistically large. */
#define HASHSIZE 997
#define T_UNDEF -1
#define T_PROTOCOL 0
#define T_CONST 1
#define T_VAR 2
#define T_SYSCONST 3
#define EOS 0
struct symbol
{
int type;
int lineno;
char *text;
struct symbol *next;
struct symbol *allocnext;
};
typedef struct symbol *Symbol;
void symbolsInit (void);
void symbolsDone (void);
Symbol get_symb (void);
void free_symb (Symbol s);
void insert (Symbol s);
Symbol lookup (char *s);
void symbolPrint (Symbol s);
Symbol symbolSysConst (char *str);
#endif

269
src/tac.c Normal file
View File

@ -0,0 +1,269 @@
#include <stdio.h>
#include "tac.h"
#include "memory.h"
extern int yylineno;
static Tac allocatedTacs;
void
tacInit (void)
{
allocatedTacs = NULL;
}
void
tacDone (void)
{
Tac ts, tf;
ts = allocatedTacs;
while (ts != NULL)
{
tf = ts;
ts = ts->allnext;
memFree (tf, sizeof (struct tacnode));
}
}
Tac
tacCreate (int op)
{
/* maybe even store in scrapping list, so we could delete them
* all later */
Tac t = memAlloc (sizeof (struct tacnode));
t->allnext = allocatedTacs;
allocatedTacs = t;
t->lineno = yylineno;
t->op = op;
t->next = NULL;
t->prev = NULL;
t->tac1 = NULL;
t->tac2 = NULL;
t->tac3 = NULL;
return t;
}
Tac
tacString (char *s)
{
Tac t;
t = tacCreate (TAC_STRING);
t->str1 = s;
return t;
}
Tac
tacJoin (int op, Tac t1, Tac t2, Tac t3)
{
Tac t;
t = tacCreate (op);
t->tac1 = t1;
t->tac2 = t2;
t->tac3 = t3;
return t;
}
Tac
tacCat (Tac t1, Tac t2)
{
Tac t1e;
if (t1 == NULL)
{
if (t2 == NULL)
return NULL;
else
return t2;
}
else
{
t1e = t1;
while (t1e->next != NULL)
t1e = t1e->next;
t1e->next = t2;
if (t2 != NULL)
{
t2->prev = t1e;
}
return t1;
}
}
/* in: a list. out: a tuple (for e.g. associativity)
* Effectively, this defines how we interpret tuples with
* more than two components.
*/
Tac
tacTuple (Tac taclist)
{
Tac tc;
/* check for single node */
if (taclist->next == NULL)
{
/* just return */
tc = taclist;
}
else
{
/* otherwise, write as (x,(y,(z,..))) */
tc = tacCreate (TAC_TUPLE);
tc->tac1 = taclist;
tc->tac2 = tacTuple (taclist->next);
/* unlink list */
tc->tac1->next = NULL;
tc->tac2->prev = NULL;
}
return tc;
}
/*
* tacPrint
* Print the tac. Only for debugging purposes.
*/
void
tacPrint (Tac t)
{
if (t == NULL)
return;
switch (t->op)
{
case TAC_PROTOCOL:
printf ("protocol %s (", t->sym1->text);
tacPrint (t->tac3);
printf (")\n{\n");
tacPrint (t->tac2);
printf ("};\n");
break;
case TAC_ROLE:
printf ("role %s\n{\n", t->sym1->text);
tacPrint (t->tac2);
printf ("};\n");
break;
case TAC_READ:
printf ("read");
if (t->sym1 != NULL)
{
printf ("_%s", t->sym1->text);
}
printf ("(");
tacPrint (t->tac2);
printf (");\n");
break;
case TAC_SEND:
printf ("send");
if (t->sym1 != NULL)
{
printf ("_%s", t->sym1->text);
}
printf ("(");
tacPrint (t->tac2);
printf (");\n");
break;
case TAC_CLAIM:
printf ("claim");
if (t->sym1 != NULL)
{
printf ("_%s", t->sym1->text);
}
printf ("(");
tacPrint (t->tac2);
printf (");\n");
break;
case TAC_CONST:
printf ("const ");
tacPrint (t->tac1);
if (t->tac2 != NULL)
{
printf (" : ");
tacPrint (t->tac2);
}
printf (";\n");
break;
case TAC_VAR:
printf ("var ");
tacPrint (t->tac1);
if (t->tac2 != NULL)
{
printf (" : ");
tacPrint (t->tac2);
}
printf (";\n");
break;
case TAC_UNDEF:
printf ("undefined");
if (t->next != NULL)
printf (",");
break;
case TAC_STRING:
printf ("%s", t->sym1->text);
if (t->next != NULL)
printf (",");
break;
case TAC_TUPLE:
printf ("(");
tacPrint (t->tac1);
printf (",");
tacPrint (t->tac2);
printf (")");
break;
case TAC_ENCRYPT:
printf ("{");
tacPrint (t->tac1);
printf ("}");
tacPrint (t->tac2);
if (t->next != NULL)
{
printf (",");
t = t->next;
tacPrint (t);
}
break;
case TAC_RUN:
printf ("run ");
tacPrint (t->tac1);
printf ("(");
tacPrint (t->tac2);
printf (");\n");
break;
case TAC_ROLEREF:
symbolPrint (t->sym1);
printf (".");
symbolPrint (t->sym2);
break;
case TAC_COMPROMISED:
printf ("compromised ");
tacPrint (t->tac1);
printf (";\n");
break;
case TAC_SECRET:
printf ("secret ");
tacPrint (t->tac1);
printf (";\n");
break;
case TAC_INVERSEKEYS:
printf ("inversekeys (");
tacPrint (t->tac1);
printf (",");
tacPrint (t->tac2);
printf (");\n");
break;
case TAC_UNTRUSTED:
printf ("untrusted ");
tacPrint (t->tac1);
printf (";\n");
break;
default:
printf ("[??]");
}
/* and any other stuff */
if (t->next != NULL)
{
tacPrint (t->next);
}
}

69
src/tac.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef TAC_H
#define TAC_H
#include "symbols.h"
/*
* TAC instructions
*/
#define TAC_UNDEF 0
#define TAC_SYM 1
#define TAC_TUPLE 3
#define TAC_ENCRYPT 4
#define TAC_VAR 7
#define TAC_CONST 8
#define TAC_READ 9
#define TAC_SEND 10
#define TAC_CLAIM 11
#define TAC_FUNC 12
#define TAC_STRING 13
#define TAC_ROLE 14
#define TAC_PROTOCOL 15
#define TAC_RUN 16
#define TAC_ROLEREF 17
#define TAC_SECRET 18
#define TAC_INVERSEKEYS 19
#define TAC_UNTRUSTED 20
#define TAC_COMPROMISED 21
#define TAC_USERTYPE 22
struct tacnode
{
struct tacnode *next;
struct tacnode *prev;
struct tacnode *allnext;
int op;
int lineno;
union
{
Symbol sym1;
struct tacnode *tac1;
char *str1;
};
union
{
Symbol sym2;
struct tacnode *tac2;
char *str2;
};
union
{
Symbol sym3;
struct tacnode *tac3;
char *str3;
};
};
typedef struct tacnode *Tac;
void tacInit (void);
void tacDone (void);
Tac tacCreate (int op);
Tac tacSymb (char *s);
Tac tacJoin (int op, Tac t1, Tac t2, Tac t3);
Tac tacTuple (Tac taclist);
Tac tacCat (Tac t1, Tac t2);
void tacPrint (Tac t);
#endif

702
src/termlists.c Normal file
View File

@ -0,0 +1,702 @@
#include <stdlib.h>
#include <stdio.h>
#include "termlists.h"
#include "debug.h"
#include "memory.h"
/* system constants.
* declared in compiler.c
*/
extern Term TERM_Function;
extern Term TERM_Hidden;
void
termlistsInit (void)
{
return;
}
void
termlistsDone (void)
{
return;
}
/* inline candidate */
Termlist
makeTermlist ()
{
return (Termlist) memAlloc (sizeof (struct termlist));
}
/*
termlistDuplicate
A deep copy.
*/
Termlist
termlistDuplicate (Termlist tl)
{
Termlist newtl;
if (tl == NULL)
return NULL;
newtl = makeTermlist ();
newtl->term = termDuplicate (tl->term);
newtl->prev = NULL;
newtl->next = termlistDuplicate (tl->next);
if (newtl->next != NULL)
(newtl->next)->prev = newtl;
return newtl;
}
/*
termlistShallow
A shallow copy, because I gather we won't be modifying any terms, only
termlists. Oh, and it reverses the order :) Don't forget!
*/
Termlist
termlistShallow (Termlist tl)
{
Termlist newtl;
newtl = NULL;
while (tl != NULL)
{
newtl = termlistAdd (newtl, tl->term);
tl = tl->next;
}
return newtl;
}
/*
termlistDelete
(shallow)
*/
void
termlistDelete (Termlist tl)
{
if (tl == NULL)
return;
termlistDelete (tl->next);
memFree (tl, sizeof (struct termlist));
}
/*
termlistDestroy
(deep)
*/
void
termlistDestroy (Termlist tl)
{
if (tl == NULL)
return;
termlistDestroy (tl->next);
termDelete (tl->term);
memFree (tl, sizeof (struct termlist));
}
/*
inTermlist
check whether a term occurs in a termlist
*/
int
inTermlist (Termlist tl, Term term)
{
if (tl == NULL)
{
if (term == NULL)
return 1;
else
return 0;
}
else
{
if (isTermEqual (tl->term, term))
return 1;
else
return inTermlist (tl->next, term);
}
}
/* are all elements of list 1 in list 2, and vice versa?
Note that we assume unique elements !
*/
int
isTermlistEqual (Termlist tl1, Termlist tl2)
{
if (termlistLength (tl1) != termlistLength (tl2))
return 0;
while (tl2 != NULL)
{
if (!inTermlist (tl1, tl2->term))
return 0;
tl2 = tl2->next;
}
return 1;
}
/*
termlistAdd
Adds a term. Duplicates are allowed.
A new list pointer is returned.
*/
Termlist
termlistAdd (Termlist tl, Term term)
{
Termlist newtl;
newtl = makeTermlist ();
newtl->term = term;
newtl->next = tl;
if (tl == NULL)
{
newtl->prev = NULL;
}
else
{
newtl->prev = tl->prev;
if (newtl->prev != NULL)
(newtl->prev)->next = newtl;
tl->prev = newtl;
}
return newtl;
}
/*
termlistAppend
Appends a term to the end of the list. Duplicates are allowed.
A new list pointer is returned.
*/
Termlist
termlistAppend (const Termlist tl, const Term term)
{
Termlist newtl;
Termlist scantl;
newtl = makeTermlist ();
newtl->term = term;
newtl->next = NULL;
if (tl == NULL)
{
newtl->prev = NULL;
return newtl;
}
else
{
scantl = tl;
while (scantl->next != NULL)
scantl = scantl->next;
scantl->next = newtl;
newtl->prev = scantl;
}
return tl;
}
Termlist
termlistConcat (Termlist tl1, Termlist tl2)
{
if (tl1 == NULL)
return tl2;
if (tl2 == NULL)
return tl1;
Termlist scan = tl1;
while (scan->next != NULL)
scan = scan->next;
scan->next = tl2;
return tl1;
}
/*
termlistDelTerm
remove the current element from the termlist. Easier because of the
double linked list.
*/
Termlist
termlistDelTerm (Termlist tl)
{
Termlist newhead;
if (tl == NULL)
return NULL;
if (tl->prev != NULL)
{
(tl->prev)->next = tl->next;
newhead = tl->prev;
while (newhead->prev != NULL)
newhead = newhead->prev;
}
else
{
newhead = tl->next;
}
if (tl->next != NULL)
(tl->next)->prev = tl->prev;
memFree (tl, sizeof (struct termlist));
return newhead;
}
Termlist
termlistConjunct (Termlist tl1, Termlist tl2)
{
Termlist newtl;
Termlist scan;
scan = tl1;
newtl = NULL;
while (scan != NULL)
{
if (inTermlist (tl2, scan->term))
newtl = termlistAdd (newtl, scan->term);
scan = scan->next;
}
return newtl;
}
Termlist
termlistConjunctType (Termlist tl1, Termlist tl2, int termtype)
{
Termlist newtl;
Termlist scan;
scan = tl1;
newtl = NULL;
while (scan != NULL)
{
if (((scan->term)->type == termtype) && (inTermlist (tl2, scan->term)))
newtl = termlistAdd (newtl, scan->term);
scan = scan->next;
}
return newtl;
}
Termlist
termlistType (Termlist tl, int termtype)
{
Termlist newtl;
Termlist scan;
scan = tl;
newtl = NULL;
while (scan != NULL)
{
if ((scan->term)->type == termtype)
newtl = termlistAdd (newtl, scan->term);
scan = scan->next;
}
return newtl;
}
void
termlistPrint (Termlist tl)
{
if (tl == NULL)
{
printf ("[Empty]");
return;
}
printf ("[");
while (tl != NULL)
{
termPrint (tl->term);
tl = tl->next;
if (tl != NULL)
printf(", ");
}
printf ("]");
}
Termlist
termlistAddVariables (Termlist tl, Term t)
{
if (t == NULL)
return tl;
t = deVar (t);
if (isTermLeaf (t))
{
if (isTermVariable (t) && !inTermlist (tl, t))
return termlistAdd (tl, t);
else
return tl;
}
else
{
if (isTermEncrypt (t))
return termlistAddVariables (termlistAddVariables (tl, t->op),
t->key);
else
return
termlistAddVariables (termlistAddVariables (tl, t->op1), t->op2);
}
}
Termlist
termlistAddRealVariables (Termlist tl, Term t)
{
if (t == NULL)
return tl;
if (realTermLeaf (t))
{
if (realTermVariable (t))
{
Term tbuf = t->subst;
t->subst = NULL;
if (!inTermlist (tl,t))
{
tl = termlistAdd (tl,t);
}
t->subst = tbuf;
return termlistAddRealVariables (tl,t->subst);
}
else
{
return tl;
}
}
else
{
if (realTermEncrypt (t))
return termlistAddVariables (termlistAddVariables (tl, t->op),
t->key);
else
return
termlistAddVariables (termlistAddVariables (tl, t->op1), t->op2);
}
}
Termlist
termlistAddBasic (Termlist tl, Term t)
{
if (t == NULL)
return tl;
if (!isTermLeaf (t))
{
if (isTermEncrypt (t))
return termlistAddBasic (termlistAddBasic (tl, t->op), t->key);
else
return termlistAddBasic (termlistAddBasic (tl, t->op1), t->op2);
}
else
{
if (!inTermlist (tl, t))
{
return termlistAdd (tl, t);
}
}
return tl;
}
Termlist
termlistAddBasics (Termlist tl, Termlist scan)
{
while (scan != NULL)
{
tl = termlistAddBasic (tl, scan->term);
scan = scan->next;
}
return tl;
}
/*
* termlistMinusTerm
*
* Remove a term from a termlist, and yield a new termlist pointer.
* Semantics: remove the first occurrence of the term.
*/
Termlist
termlistMinusTerm (Termlist tl, Term t)
{
Termlist scan;
scan = tl;
while (scan != NULL)
{
if (isTermEqual (scan->term, t))
return termlistDelTerm (scan);
else
scan = scan->next;
}
return tl;
}
int
termlistLength (Termlist tl)
{
int i = 0;
while (tl != NULL)
{
tl = tl->next;
i++;
}
return i;
}
/*
inverseKey
Gives the inverse Key of some term (which is used to encrypt something), as is defined
by the termlist, which is a list of key1,key1inv, key2, key2inv, etc...
*/
Term
inverseKey (Termlist inverses, Term key)
{
key = deVar (key);
/* is this a function application? i.e. hash? */
if (isTermLeaf (key) && inTermlist (key->stype, TERM_Function))
{
/* functions cannot be inverted by default */
return termDuplicate (TERM_Hidden);
}
/* check for the special case first: when it is effectively a function application */
if (isTermEncrypt (key) && isTermLeaf (key->key)
&& inTermlist (deVar (key->key)->stype, TERM_Function))
{
/* we are scanning for functions */
/* scan the list */
/* key is function application kk(op), or {op}kk */
Term funKey (Term orig, Term newk)
{
/* in: {op}kk, nk
* out: {op'}nk */
return makeTermEncrypt (termDuplicate (orig->op),
termDuplicate (newk));
}
while (inverses != NULL && inverses->next != NULL)
{
if (isTermEqual (key->key, inverses->term))
return funKey (key, inverses->next->term);
if (isTermEqual (key->key, inverses->next->term))
return funKey (key, inverses->term);
inverses = inverses->next->next;
}
}
else
{
/* scanning for a direct inverse */
/* scan the list */
while (inverses != NULL && inverses->next != NULL)
{
if (isTermEqual (key, inverses->term))
return termDuplicate (inverses->next->term);
if (isTermEqual (key, inverses->next->term))
return termDuplicate (inverses->term);
inverses = inverses->next->next;
}
}
return termDuplicate (key); /* defaults to symmetrical */
}
/*
* localTerm
*
* Creates a term local to a run.
* We assume that at this point, no variables have been instantiated yet that occur in this term.
* We also assume that fromlist, tolist and locals only hold real leaves.
*/
Term
termLocal (const Term t, Termlist fromlist, Termlist tolist,
const Termlist locals, const int runid)
{
if (t == NULL)
return NULL;
if (realTermLeaf (t))
{
while (fromlist != NULL && tolist != NULL)
{
if (isTermEqual (fromlist->term, t))
{
// matches!
return tolist->term;
}
fromlist = fromlist->next;
tolist = tolist->next;
}
if (inTermlist (locals, t))
{
// return termRunid(t,runid);
}
return t;
}
else
{
Term newt = termDuplicate (t);
if (realTermTuple (t))
{
newt->op1 = termLocal (t->op1, fromlist, tolist, locals, runid);
newt->op2 = termLocal (t->op2, fromlist, tolist, locals, runid);
}
else
{
newt->op = termLocal (t->op, fromlist, tolist, locals, runid);
newt->key = termLocal (t->key, fromlist, tolist, locals, runid);
}
return newt;
}
}
/*
* termlistLocal
*
* We expand the previous concept to termlists.
*/
Termlist
termlistLocal (Termlist tl, const Termlist fromlist, const Termlist tolist,
const Termlist locals, int runid)
{
Termlist newtl = NULL;
while (tl != NULL)
{
newtl =
termlistAdd (newtl,
termLocal (tl->term, fromlist, tolist, locals, runid));
tl = tl->next;
}
return newtl;
}
/*
* Check whether tl2 is contained in tl1.
*/
int
termlistContained (const Termlist tlbig, Termlist tlsmall)
{
while (tlsmall != NULL)
{
if (!inTermlist (tlbig, tlsmall->term))
return 0;
tlsmall = tlsmall->next;
}
return 1;
}
/*
* Determine whether a variable has been substituted with something with
* the right type.
*/
int
validSubst (const int matchmode, const Term term)
{
if (!realTermVariable (term) || term->subst == NULL)
return 1;
else
{
switch (matchmode)
{
case 0: /* real type match */
return realTermLeaf (term->subst)
&& termlistContained (term->stype, term->subst->stype);
case 1: /* basic type match */
/* subst must be a leaf */
/* TODO: what about functions? */
return realTermLeaf (term->subst);
case 2: /* no type match */
/* anything goes */
return 1;
default:
return 0;
}
}
}
/*
* termFunction
*
* An assist function that helps to simulate Term->Term functions, using
* termlists. One termlist functions as the domain, and the other as the
* range.
*
* Extending a function with a value y = f(x) amounts to extending the
* domain with x, and the range with y.
*/
Term
termFunction (Termlist fromlist, Termlist tolist, Term tx)
{
while (fromlist != NULL && tolist != NULL)
{
if (isTermEqual (fromlist->term, tx))
{
return tolist->term;
}
fromlist = fromlist->next;
tolist = tolist->next;
}
return NULL;
}
/*
* Forward the termlist pointer to the last item
*/
Termlist
termlistForward (Termlist tl)
{
if (tl == NULL)
{
return NULL;
}
else
{
while (tl->next != NULL)
{
tl = tl->next;
}
return tl;
}
}

48
src/termlists.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef TERMLISTS
#define TERMLISTS
#include "terms.h"
struct termlist
{
Term term;
struct termlist *next;
struct termlist *prev;
};
typedef struct termlist *Termlist;
void termlistsInit (void);
void termlistsDone (void);
Termlist termlistDuplicate (Termlist tl);
Termlist termlistShallow (Termlist tl);
void termlistDelete (Termlist tl);
void termlistDestroy (Termlist tl);
void termlistPrint (Termlist tl);
int inTermlist (Termlist tl, Term term);
int isTermlistEqual (Termlist tl1, Termlist tl2);
Termlist termlistAdd (Termlist tl, Term term);
Termlist termlistAppend (const Termlist tl, const Term term);
Termlist termlistConcat (Termlist tl1, Termlist tl2);
Termlist termlistDelTerm (Termlist tl);
Termlist termlistConjunct (Termlist tl1, Termlist tl2);
Termlist termlistConjunctType (Termlist tl1, Termlist tl2, int termtype);
Termlist termlistType (Termlist tl, int termtype);
Termlist termlistAddVariables (Termlist tl, Term t);
Termlist termlistAddRealVariables (Termlist tl, Term t);
Termlist termlistAddBasic (Termlist tl, Term t);
Termlist termlistAddBasics (Termlist tl, Termlist scan);
Termlist termlistMinusTerm (Termlist tl, Term t);
int termlistLength (Termlist tl);
Term inverseKey (Termlist inverses, Term key);
Term termLocal (const Term t, Termlist fromlist, Termlist tolist,
const Termlist locals, const int runid);
Termlist termlistLocal (Termlist tl, const Termlist fromlist,
const Termlist tolist, const Termlist locals,
const int runid);
int termlistContained (const Termlist tlbig, Termlist tlsmall);
int validSubst (const int matchmode, const Term term);
Term termFunction (Termlist fromlist, Termlist tolist, Term tx);
Termlist termlistForward (Termlist tl);
#endif

680
src/terms.c Normal file
View File

@ -0,0 +1,680 @@
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "terms.h"
#include "debug.h"
#include "memory.h"
#include "ctype.h"
/* external definitions */
extern Term TERM_Function;
extern int inTermlist (); // suppresses a warning, but at what cost?
extern int globalLatex;
/* forward declarations */
void indent (void);
/* useful macros */
#define RID_UNDEF MIN_INT
/* main code */
/* Two types of terms: general, and normalized. Normalized rewrites all
tuples to (x,(y,z))..NULL form, making list traversal easy. */
void
termsInit (void)
{
return;
}
void
termsDone (void)
{
return;
}
Term
makeTerm ()
{
return (Term) memAlloc (sizeof (struct term));
}
Term
makeTermEncrypt (Term t1, Term t2)
{
Term term = makeTerm ();
term->type = ENCRYPT;
term->stype = NULL;
term->op = t1;
term->key = t2;
return term;
}
Term
makeTermTuple (Term t1, Term t2)
{
if (t1 == NULL)
{
if (t2 == NULL)
{
#ifdef DEBUG
debug (5, "Trying to make a tuple node with an empty term.");
#endif
return NULL;
}
else
return t2;
}
if (t2 == NULL)
{
return t1;
}
Term tt = makeTerm ();
tt->type = TUPLE;
tt->stype = NULL;
tt->op1 = t1;
tt->op2 = t2;
return tt;
}
Term
makeTermType (const int type, const Symbol symb, const int runid)
{
Term term = makeTerm ();
term->type = type;
term->stype = NULL;
term->subst = NULL;
term->symb = symb;
term->runid = runid;
return term;
}
/* deVar unwraps any substitutions.
*
* For speed, it is a macro. Sometimes it will call
* deVarScan to do the actual unwinding.
*/
Term
deVarScan (Term t)
{
while (realTermVariable (t) && t->subst != NULL)
t = t->subst;
return t;
}
int
hasTermVariable (Term term)
{
if (term == NULL)
return 0;
term = deVar (term);
if (realTermLeaf (term))
return realTermVariable (term);
else
{
if (realTermTuple (term))
return (hasTermVariable (term->op1) || hasTermVariable (term->op2));
else
return (hasTermVariable (term->op) || hasTermVariable (term->key));
}
}
/*
isTermEqualFn(term,term)
Tests whether two terms are completely identical. This also includes
variables. This is the recursive function.
We assume the term is normalized, e.g. no tupling has direct
subtupling.
Out: 0 unequal, 1 equal
*/
int
isTermEqualFn (Term term1, Term term2)
{
term1 = deVar (term1);
term2 = deVar (term2);
if (term1 == term2)
return 1;
if ((term1 == NULL) || (term2 == NULL))
return 0;
if (term1->type != term2->type)
{
return 0;
}
if (realTermLeaf (term1))
{
return (term1->symb == term2->symb && term1->runid == term2->runid);
}
else
{
/* ENCRYPT or TUPLE */
if (realTermEncrypt (term1))
{
/* for optimization of encryption equality, we compare
operator 2 first (we expect it to be a smaller term)
*/
return (isTermEqualFn (term1->key, term2->key) &&
isTermEqualFn (term1->op, term2->op));
}
else
{
/* tuple */
return (isTermEqualFn (term1->op1, term2->op1) &&
isTermEqualFn (term1->op2, term2->op2));
}
}
}
int
termOccurs (Term t, Term tsub)
{
t = deVar (t);
tsub = deVar (tsub);
if (isTermEqual (t, tsub))
return 1;
if (realTermLeaf (t))
return 0;
if (realTermTuple (t))
return (termOccurs (t->op1, tsub) || termOccurs (t->op2, tsub));
else
return (termOccurs (t->op, tsub) || termOccurs (t->key, tsub));
}
void
termPrint (Term term)
{
if (term == NULL)
{
printf ("Empty term");
return;
}
#ifdef DEBUG
if (!DEBUGL (1))
{
term = deVar (term);
}
#else
term = deVar (term);
#endif
if (realTermLeaf (term))
{
symbolPrint (term->symb);
if (realTermVariable (term))
printf ("V");
if (term->runid >= 0)
{
if (globalLatex)
printf ("\\sharp%i", term->runid);
else
printf ("#%i", term->runid);
}
if (term->subst != NULL)
{
if (globalLatex)
printf ("\\rightarrow");
else
printf ("->");
termPrint (term->subst);
}
}
if (realTermTuple (term))
{
printf ("(");
while (realTermTuple (term))
{
termPrint (term->op1);
printf (",");
term = term->op2;
if (!realTermTuple (term))
termPrint (term);
}
printf (")");
return;
}
if (realTermEncrypt (term))
{
if (isTermLeaf (term->key)
&& inTermlist (term->key->stype, TERM_Function))
{
/* function application */
termPrint (term->key);
printf ("(");
termPrint (term->op);
printf (")");
}
else
{
/* normal encryption */
if (globalLatex)
{
printf ("\\{");
termPrint (term->op);
printf ("\\}_{");
termPrint (term->key);
printf ("}");
}
else
{
printf ("{");
termPrint (term->op);
printf ("}");
termPrint (term->key);
}
}
}
}
/*
Duplicate
make a deep copy of a term, but not of leaves.
*/
Term
termDuplicate (const Term term)
{
Term newterm;
if (term == NULL)
return NULL;
if (realTermLeaf (term))
return term;
newterm = (Term) memAlloc (sizeof (struct term));
newterm->type = term->type;
if (realTermEncrypt (term))
{
newterm->op = termDuplicate (term->op);
newterm->key = termDuplicate (term->key);
}
else
{
newterm->op1 = termDuplicate (term->op1);
newterm->op2 = termDuplicate (term->op2);
}
return newterm;
}
/*
DuplicateDeep
make a deep copy of a term, and also of leaves.
*/
Term
termDuplicateDeep (const Term term)
{
Term newterm;
if (term == NULL)
return NULL;
newterm = (Term) memAlloc (sizeof (struct term));
if (realTermLeaf (term))
{
memcpy (newterm, term, sizeof (struct term));
}
else
{
newterm->type = term->type;
if (realTermEncrypt (term))
{
newterm->op = termDuplicateDeep (term->op);
newterm->key = termDuplicateDeep (term->key);
}
else
{
newterm->op1 = termDuplicateDeep (term->op1);
newterm->op2 = termDuplicateDeep (term->op2);
}
}
return newterm;
}
/*
* DuplicateUV
*
* Remove all instantiated variables on the way down.
*/
Term
termDuplicateUV (Term term)
{
Term newterm;
if (term == NULL)
return NULL;
term = deVar (term);
if (realTermLeaf (term))
return term;
newterm = (Term) memAlloc (sizeof (struct term));
newterm->type = term->type;
if (realTermEncrypt (term))
{
newterm->op = termDuplicateUV (term->op);
newterm->key = termDuplicateUV (term->key);
}
else
{
newterm->op1 = termDuplicateUV (term->op1);
newterm->op2 = termDuplicateUV (term->op2);
}
return newterm;
}
/*
realTermDuplicate
make a deep copy of a term, also of leaves.
*/
Term
realTermDuplicate (const Term term)
{
Term newterm;
if (term == NULL)
return NULL;
newterm = (Term) memAlloc (sizeof (struct term));
if (realTermLeaf (term))
{
memcpy (newterm, term, sizeof (struct term));
}
else
{
newterm->type = term->type;
if (realTermEncrypt (term))
{
newterm->op = realTermDuplicate (term->op);
newterm->key = realTermDuplicate (term->key);
}
else
{
newterm->op1 = realTermDuplicate (term->op1);
newterm->op2 = realTermDuplicate (term->op2);
}
}
return newterm;
}
/*
termDelete
Removes a term and deallocates memory
*/
void
termDelete (const Term term)
{
if (term != NULL && !realTermLeaf (term))
{
if (realTermEncrypt (term))
{
termDelete (term->op);
termDelete (term->key);
}
else
{
termDelete (term->op1);
termDelete (term->op2);
}
memFree (term, sizeof (struct term));
}
}
/*
termNormalize
avoids problems with associativity by rewriting every ((x,y),z) to
(x,y,z)), i.e. a normal form for terms, after which equality is
okay.
*/
void
termNormalize (Term term)
{
term = deVar (term);
if (term == NULL || realTermLeaf (term))
return;
if (realTermEncrypt (term))
{
termNormalize (term->op);
termNormalize (term->key);
}
else
{
/* normalize left hand first,both for tupling and for
encryption */
termNormalize (term->op1);
/* check for ((x,y),z) construct */
if (realTermTuple (term->op1))
{
/* temporarily store the old terms */
Term tx = (term->op1)->op1;
Term ty = (term->op1)->op2;
Term tz = term->op2;
/* move node */
term->op2 = term->op1;
/* construct (x,(y,z)) version */
term->op1 = tx;
(term->op2)->op1 = ty;
(term->op2)->op2 = tz;
}
termNormalize (term->op2);
}
}
Term
termRunid (Term term, int runid)
{
if (term == NULL)
return NULL;
if (realTermLeaf (term))
{
/* leaf */
if (term->runid == runid)
return term;
else
{
Term newt = termDuplicate (term);
newt->runid = runid;
return newt;
}
}
else
{
/* anything else, recurse */
if (realTermEncrypt (term))
{
return makeTermEncrypt (termRunid (term->op, runid),
termRunid (term->key, runid));
}
else
{
return makeTermTuple (termRunid (term->op1, runid),
termRunid (term->op2, runid));
}
}
}
/* tupleCount yields the size of the top tuple in the term */
int
tupleCount (Term tt)
{
if (tt == NULL)
{
return 0;
}
else
{
deVar (tt);
if (!realTermTuple (tt))
{
return 1;
}
else
{
return (tupleCount (tt->op1) + tupleCount (tt->op2));
}
}
}
/* tupleProject yields the projection pi (0 .. n-1) on a top tuple. Returns
* NULL if the range is incorrect. */
Term
tupleProject (Term tt, int n)
{
if (tt == NULL)
{
return NULL;
}
deVar (tt);
if (!realTermTuple (tt))
{
if (n > 0)
{
/* no tuple, adressing error */
return NULL;
}
else
{
/* no tuple */
return tt;
}
}
else
{
/* there is a tuple to traverse */
int left = tupleCount (tt->op1);
if (n >= left)
{
/* it's in the right hand side */
return tupleProject (tt->op2, n - left);
}
else
{
/* left hand side */
return tupleProject (tt->op1, n);
}
}
}
/* number of elements in a term.
*
* Currently, the encryption operator is weighed as well.
*/
int
termSize(Term t)
{
if (t == NULL)
{
return 0;
}
t = deVar(t);
if (realTermLeaf(t))
{
return 1;
}
else
{
if (realTermEncrypt(t))
{
return 1 + termSize(t->op) + termSize(t->key);
}
else
{
return termSize(t->op1) + termSize(t->op2);
}
}
}
/* Yield some sort of distance between two terms, as a float between 0 and 1.
*/
float
termDistance(Term t1, Term t2)
{
/* First the special cases: no equal subterms, completely equal */
if (isTermEqual(t1,t2))
return 1;
t1 = deVar(t1);
t2 = deVar(t2);
int t1s = termSize(t1);
int t2s = termSize(t2);
if (t1 == NULL || t2 == NULL)
{
return 0;
}
if (t1->type != t2->type)
{
/* unequal type, maybe one is a subterm of the other? */
if (t1s > t2s && termOccurs(t1,t2))
{
return (float) t2s / t1s;
}
if (t2s > t1s && termOccurs(t2,t1))
{
return (float) t1s / t2s;
}
return 0;
}
else
{
/* equal types */
if (isTermLeaf(t1))
{
/* we had established before that they are not equal */
return 0;
}
else
{
/* non-leaf recurse */
if (isTermEncrypt(t1))
{
/* encryption */
return (termDistance(t1->op, t2->op) + termDistance(t1->key, t2->key)) / 2;
}
else
{
return (termDistance(t1->op1, t2->op1) + termDistance(t1->op2, t2->op2)) / 2;
}
}
}
}

93
src/terms.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef TERMS
#define TERMS
#include "symbols.h"
#define GLOBAL 1
#define VARIABLE 2
#define LEAF 3 // type <= LEAF means it's a leaf, nkay?
#define ENCRYPT 4
#define TUPLE 5
struct term
{
/* basic : name,runid
encrypt: op,key
tuple : op,next
*/
int type;
void *stype; // only for leaf, termlist pointer
struct term *subst; // only for variable/leaf, substitution term
union
{
Symbol symb;
struct term *op;
struct term *op1;
struct term *next; // for alternative memory management
};
union
{
int runid;
struct term *key;
struct term *op2;
};
};
typedef struct term *Term;
void termsInit (void);
void termsDone (void);
Term makeTermEncrypt (Term t1, Term t2);
Term makeTermTuple (Term t1, Term t2);
Term makeTermType (const int type, const Symbol symb, const int runid);
Term deVarScan (Term t);
#define substVar(t) ((t != NULL && t->type == VARIABLE && t->subst != NULL) ? 1 : 0)
#define deVar(t) ( substVar(t) ? deVarScan(t->subst) : t)
#define realTermLeaf(t) (t != NULL && t->type <= LEAF)
#define realTermTuple(t) (t != NULL && t->type == TUPLE)
#define realTermEncrypt(t) (t != NULL && t->type == ENCRYPT)
#define realTermVariable(t) (t != NULL && t->type == VARIABLE)
#define isTermLeaf(t) realTermLeaf(deVar(t))
#define isTermTuple(t) realTermTuple(deVar(t))
#define isTermEncrypt(t) realTermEncrypt(deVar(t))
#define isTermVariable(t) realTermVariable(deVar(t))
#define isTermEqual(t1,t2) ((substVar(t1) || substVar(t2)) \
? isTermEqualFn(t1,t2) \
: ( \
(t1 == t2) \
? 1 \
: ( \
(t1 == NULL || t2 == NULL || t1->type != t2->type) \
? 0 \
: ( \
realTermLeaf(t1) \
? (t1->symb == t2->symb && t1->runid == t2->runid) \
: ( \
realTermEncrypt(t2) \
? (isTermEqualFn(t1->key, t2->key) && \
isTermEqualFn(t1->op, t2->op)) \
: (isTermEqualFn(t1->op1, t2->op1) && \
isTermEqualFn(t1->op2, t2->op2)) \
) \
) \
) \
) \
)
int hasTermVariable (Term term);
int isTermEqualFn (Term term1, Term term2);
int termOccurs (Term t, Term tsub);
void termPrint (Term term);
Term termDuplicate (const Term term);
Term termDuplicateDeep (const Term term);
Term termDuplicateUV (Term term);
void termDelete (const Term term);
void termNormalize (Term term);
Term termRunid (Term term, int runid);
int tupleCount (Term tt);
Term tupleProject (Term tt, int n);
int termSize(Term t);
float termDistance(Term t1, Term t2);
#endif

22
src/testl Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
#
# Shell script to display the latex output relatively quickly. For
# internal testing only, as it depends on the spdl subdirectory.
#
# Usage example:
#
# ./testl ns3
#
file=spdl/$1.spdl outfile=tempattack
if [ -f $file ]
then
./scyther --latex <$file >$outfile.tex
latex $outfile.tex
xdvi $outfile.dvi
else
echo "No file $file found."
fi

80
src/todo.txt Normal file
View File

@ -0,0 +1,80 @@
- Remove stupid preamble postamble stuff, or maybe integrate this behaviour
into some switch, where default would be a standalone latex file, and
another option would generate a file that can be included.
- Variables have to be 'saved' and 'stored' into some structure. However, for
this we need a global list of all variables, which is not available at the
moment. The compiler and run instantiator should maintain such a list, and
then we could save it into a struct with three lists. (from,to,empty)
This will need a sys allVariables list.
- Timer output is broken for values e.g. above an hour. Fix or remove
altogether.
- ns3 doesn't even reach a claim in --cl and -t8. Check.
- in Runs.c, revise 'untrustedAgent' to cope with some weird exceptions.
- CLP: variables in keys must be branched: maybe even in three situations
(have key and contents, have inverse key and content, nothing)
- Implement delayed protocol compiler (on run demand only).
- Implement run knowledge, and use this in protocol compiler.
- Remove any remaining global variables, if any.
- When choosing agents for runs (with an initial read), it does not make
sense to choose untrusted agents.
- Introduce 'Ticket' default type in the compiler, along with some
handling for that.
- Make a shell script 'test $filename $commandline'
Generates a $test-$date.out and $test-$date.err. Useful for storing
test data.
- How should claims behave (trusted/untrusted) wrt uninstantiated
agents? Branch again? That's what is causing the nsl3-var problem.
- The 'choose' operator must always be typed, I think.
- Synchronisation test can be expensive, because a good protocol will
yield few such tests, and a bad protocol will prune most traces after
failure. The performance loss will only be 'felt' when the whole state
space is explored (-p0), which is only used for theoretical tests.
- The woolam-ce is incorrect because it is illegal to have a variable
term in a key that is read, by CMV semantics. I don't know what it
means for CE semantics (yet).
- Idea: run bla.bla(params) [compromised <localterm> [,<localterm>] ];
1. These local terms are given to the intruder. Technically this
should only happen _after_ they are first sent in the run. Maybe add
this to send semantics: if termOccurs(sendterm, compromisedterm) then
add compromisedterm to M, remove compromisedterm from list of terms to
compromise.
2. All claims in the run are ignored (add untrusted flag to run)
Alternative: run x.x(x) untrusted; or just compromised, to give up
all constants.
Note this is not sufficient yet, because it does not consider any
partner runs. Maybe declare a 'compromised' section first; other runs
will only activate after these have completed. Note this is much more
expensive.
- Issue: how do untrusted claims work in the context of an intruder?
Claim must be checked if it can be solved such that at least one of
the agents is trusted.
- Fix the first environment read with a special (hidden) label.
1. Hide it or print differently in output.
2. Ensure typed matching for it, even when using -m1 switch.
- Woolam-ce gives nothing. But then again, it's a wrong impl.
- consider option -finline-functions for gcc, test.
- Currently, match_basic unrolls substitutions to compare message with
the forbidden list, but I don't think that it is required. Test.
- -m2 is much better with a lot of variables. Compare this to unfolding
of the runs with -t4 -m0/1.
- Global/protocol variables should not exist in the current system.
- File freopen stuff, instead of this sdtin stuff.
- Solve the 'version' issue. How is it defined?
- run nsl.initiator(alice, all Agent) constructs?
- 'all' would generate the roles with the corresponding type.
- or maybe for clarity/complexity control: use 'runs' for constructs
with 'all' in it.
- Constraints might be a part of a knowledge thing, because with we
might now have a number of local knowledge sets, each with their own
constraint sets. That doesn't make it easier though :( and will cause
some performance loss I suppose. Each local set has to remain
solveable as well.
- Maybe function application ought to be a different basic term type.
- After role construction, msc consistency can be checked.
- Make sure module knowledge has an interface instead of reference to
internals (i.e. no ref to basic/encr)
- Reduce knowledge to a simple term list? That would simplify a number
of things, and also allow for easier addition of stuff.
- How is % notation handled in Casper?
- Vernam encryption?
- Count number of illegal injections rejected for statistics.

200
src/tracebuf.c Normal file
View File

@ -0,0 +1,200 @@
/*
* tracebuf.c
*
* trace buffer operations
*/
#include <stdio.h>
#include <stdlib.h>
#include "runs.h"
#include "memory.h"
#include "tracebuf.h"
#include "varbuf.h"
/* reconstruct the knowledge sequence, -1 if it can be done, event nr of last depending read otherwise.
* There is one exception: if it returns tb->length, the required terms are not in the last knowledge
*/
int
tracebufRebuildKnow(struct tracebuf *tb)
{
Knowledge k;
Roledef rd;
int i;
int flag;
Termlist tl;
if (tb == NULL || tb->length == 0)
{
/* stupid, but true */
return -1;
}
flag = -1;
k = knowledgeDuplicate(tb->know[0]);
i = 0;
while (i < tb->length)
{
rd = tb->event[i];
if (tb->status[i] != S_RED)
{
/* simulate execution of the event */
switch (rd->type)
{
case READ:
if (!inKnowledge (k, rd->message))
{
flag = i;
}
break;
case SEND:
knowledgeAddTerm (k, rd->message);
break;
case CLAIM:
/* TODO parse term requirements ? */
/* Probably not needed */
break;
default:
/* Anything else */
break;
}
}
/* write the new knowledge, overwriting old stuff */
knowledgeDelete (tb->know[i+1]);
tb->know[i+1] = knowledgeDuplicate (k);
i++;
}
tl = tb->requiredterms;
while (tl != NULL)
{
if (!inKnowledge (k, tl->term))
{
flag = tb->length;
}
tl = tl->next;
}
knowledgeDelete(k);
return flag;
}
/*
* traceBufInit
*
* initializes the trace buffer.
*/
struct tracebuf*
tracebufInit (void)
{
struct tracebuf *tb = (struct tracebuf *) memAlloc(sizeof(struct tracebuf));
tb->length = 0;
tb->reallength = 0;
tb->event = NULL;
tb->know = NULL;
tb->run = NULL;
tb->status = NULL;
tb->link = NULL;
tb->requiredterms = NULL;
tb->violatedclaim = 0;
tb->variables = NULL;
return tb;
}
void
tracebufDone (struct tracebuf *tb)
{
if (tb == NULL)
{
return;
}
Roledef rd;
varbufDone (tb->variables);
if (tb->length > 0)
{
int i;
i = 0;
/* note: knowledge domain is length+1 */
knowledgeDelete(tb->know[0]);
while (i < tb->length)
{
rd = tb->event[i];
termDelete (rd->from);
termDelete (rd->to);
termDelete (rd->message);
roledefDelete(rd);
knowledgeDelete(tb->know[i+1]);
i++;
}
memFree(tb->know, (i+1) * sizeof (struct knowledge*));
memFree(tb->event, i * sizeof (struct roledef*));
memFree(tb->run, i * sizeof(int));
memFree(tb->status, i * sizeof(int));
memFree(tb->link, i * sizeof(int));
}
memFree(tb, sizeof(tracebuf));
}
struct tracebuf*
tracebufSet (const System sys, int length, int claimev)
{
struct tracebuf *tb;
int i;
Roledef rd;
/* TODO For the constraint logic approach, we would simply insert
* any constant from the constraint for a variable.
*/
tb = tracebufInit();
if (length == 0)
{
return tb;
}
tb->length = length;
tb->reallength = length;
tb->variables = (Varbuf) varbufInit (sys);
tb->event = (Roledef *) memAlloc(length * sizeof(struct roledef*));
tb->status = (int *) memAlloc(length * sizeof(int));
tb->link = (int *) memAlloc(length * sizeof(int));
tb->run = (int *) memAlloc(length * sizeof(int));
tb->know = (Knowledge *) memAlloc((length + 1) * sizeof (struct knowledge*));
/* when duplicating the knowledge, we want to instantiate the variables as well
*/
tb->know[0] = knowledgeSubstDo (sys->traceKnow[0]);
i = 0;
while (i < length)
{
rd = roledefDuplicate1 (sys->traceEvent[i]);
if (rd == NULL)
{
printf("Empty event in trace at %i of %i?\n",i,length);
exit(1);
}
/* make a copy without variables */
rd->to = termDuplicateUV (rd->to);
rd->from = termDuplicateUV (rd->from);
rd->message = termDuplicateUV (rd->message);
tb->event[i] = rd;
tb->link[i] = -1;
tb->status[i] = S_UNK;
tb->run[i] = sys->traceRun[i];
tb->know[i+1] = NULL;
i++;
}
/* mark claim */
tb->violatedclaim = claimev;
tb->status[claimev] = S_OKE;
tracebufRebuildKnow (tb);
return tb;
}

27
src/tracebuf.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef TRACEBUF
#define TRACEBUF
#include "terms.h"
#include "termlists.h"
#include "knowledge.h"
#include "runs.h"
/* STATUS symbols */
#define S_UNK 0 // UNKnown : unprocessed.
#define S_OKE 1 // OKE : done, but required for the attack.
#define S_RED 2 // REDundant : is not needed for attack, we're sure.
#define S_TOD 3 // TODo : The previous suggestion REQ was too similar to RED.
// This is reserved for reads.
/*
* tracebuf struct is defined in runs.h to avoid loops.
*/
int tracebufRebuildKnow(struct tracebuf *tb);
struct tracebuf* tracebufInit (void);
void tracebufDone (struct tracebuf *tb);
struct tracebuf* tracebufSet (const System sys, int length, int claimev);
#endif

94
src/varbuf.c Normal file
View File

@ -0,0 +1,94 @@
/*
* varbuf.c
*
* Operations on a variable substitutions buffer.
* The type is actually defined in runs.h
*/
#include "memory.h"
#include "runs.h"
/*
* create a new varbuffer from the current state of the system
*/
Varbuf
varbufInit (System sys)
{
Varbuf vb;
Termlist tl;
Term termfrom, termto;
vb = (Varbuf) memAlloc(sizeof(struct varbuf));
vb->from = NULL;
vb->to = NULL;
vb->empty = NULL;
tl = sys->variables;
while (tl != NULL)
{
if (realTermVariable(tl->term))
{
/* this is actually a variable */
if (tl->term->subst == NULL)
{
/* non-instantiated */
vb->empty = termlistAdd (vb->empty, tl->term);
}
else
{
/* store instantiation */
termfrom = tl->term;
termto = termfrom->subst;
termfrom->subst = NULL; // temp disable
vb->from = termlistAdd (vb->from, termfrom);
vb->to = termlistAdd (vb->to, termto);
termfrom->subst = termto; // restore
}
}
tl = tl->next;
}
return vb;
}
/*
* copy the variable state back into the system
*/
void
varbufSet (System sys, Varbuf vb)
{
Termlist tl1, tl2;
tl1 = vb->from;
tl2 = vb->to;
while (tl1 != NULL && tl2 != NULL)
{
tl1->term->subst = tl2->term;
tl1 = tl1->next;
tl2 = tl2->next;
}
tl1 = vb->empty;
while (tl1 != NULL)
{
tl1->term->subst = NULL;
tl1 = tl1->next;
}
}
/*
* cleanup
*/
void
varbufDone (Varbuf vb)
{
if (vb != NULL)
{
termlistDelete (vb->from);
termlistDelete (vb->to);
termlistDelete (vb->empty);
memFree(vb, sizeof(struct varbuf));
}
}

10
src/varbuf.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef VARBUF
#define VARBUF
#include "runs.h"
Varbuf varbufInit (System sys);
void varbufSet (System sys, Varbuf vb);
void varbufDone (Varbuf vb);
#endif