scyther/src/arachne.c

1419 lines
28 KiB
C
Raw Normal View History

2004-08-11 10:51:17 +01:00
/**
*
2004-08-11 10:51:17 +01:00
*@file arachne.c
*
* Introduces a method for proofs akin to the Athena modelchecker
* http://www.ece.cmu.edu/~dawnsong/athena/
*
*/
2004-08-11 13:08:10 +01:00
#include "term.h"
#include "termlist.h"
2004-08-11 13:08:10 +01:00
#include "role.h"
2004-08-11 10:51:17 +01:00
#include "system.h"
#include "knowledge.h"
#include "compiler.h"
#include "states.h"
#include "mgu.h"
2004-08-11 10:51:17 +01:00
#include "arachne.h"
2004-08-14 16:59:14 +01:00
#include "error.h"
#include "claim.h"
#include "debug.h"
#include "binding.h"
2004-08-11 10:51:17 +01:00
extern Term CLAIM_Secret;
extern Term CLAIM_Nisynch;
extern Term CLAIM_Niagree;
extern Term TERM_Agent;
2004-08-18 20:43:58 +01:00
extern Term TERM_Hidden;
static System sys;
2004-08-18 21:22:33 +01:00
static Claimlist current_claim;
Protocol INTRUDER; // Pointers, to be set by the Init
Role I_M; // Same here.
Role I_F;
Role I_T;
Role I_V;
Role I_R;
Role I_E;
Role I_D;
Role I_RRS;
2004-08-11 13:08:10 +01:00
static int indentDepth;
static int max_encryption_level;
2004-08-19 13:47:53 +01:00
static int num_regular_runs;
static int num_intruder_runs;
2004-08-11 13:08:10 +01:00
struct goalstruct
{
int run;
int index;
Roledef rd;
2004-08-11 13:08:10 +01:00
};
typedef struct goalstruct Goal;
/**
* Forward declarations
*/
int iterate ();
/**
* Program code
*/
//! Init Arachne engine
void
arachneInit (const System mysys)
{
Term GVT;
Roledef rd = NULL;
Termlist tl, know0;
void add_event (int event, Term message)
{
rd = roledefAdd (rd, event, NULL, NULL, NULL, message, NULL);
}
Role add_role (const char *rolenamestring)
{
Role r;
Term rolename;
rolename = makeGlobalConstant (rolenamestring);
r = roleCreate (rolename);
r->roledef = rd;
rd = NULL;
r->next = INTRUDER->roles;
INTRUDER->roles = r;
// compute_role_variables (sys, INTRUDER, r);
return r;
}
sys = mysys; // make sys available for this module as a global
/**
* Very important: turn role terms that are local to a run, into variables.
*/
term_rolelocals_are_variables ();
/*
* Add intruder protocol roles
*/
INTRUDER = protocolCreate (makeGlobalConstant (" INTRUDER "));
GVT = makeGlobalVariable ("GlobalVariable");
add_event (SEND, GVT);
I_M = add_role ("I_M: Atomic message");
add_event (READ, NULL);
add_event (READ, NULL);
add_event (SEND, NULL);
2004-08-19 15:49:03 +01:00
I_RRS = add_role ("I_E: Encrypt");
return;
}
//! Close Arachne engine
void
arachneDone ()
{
return;
}
2004-08-11 13:08:10 +01:00
//------------------------------------------------------------------------
// Detail
//------------------------------------------------------------------------
/*
* runs[rid].step is now the number of 'valid' events within the run, but we
* call it 'length' here.
*/
#define INVALID -1
#define isGoal(rd) (rd->type == READ && !rd->internal)
#define isBound(rd) (rd->bound)
2004-08-11 13:08:10 +01:00
#define length step
//! Indent print
void
indentPrint ()
{
int i;
for (i = 0; i < indentDepth; i++)
{
if (i % 3 == 0)
eprintf ("|");
else
2004-08-19 12:37:41 +01:00
eprintf (" ");
eprintf (" ");
}
}
//! Print indented binding
void
binding_indent_print (Binding b, int flag)
{
indentPrint ();
if (flag)
eprintf ("!! ");
binding_print (b);
eprintf ("\n");
}
2004-08-19 13:47:53 +01:00
//! Wrapper for roleInstance
/**
*@return Returns the run number
*/
2004-08-19 14:09:35 +01:00
int
semiRunCreate (const Protocol p, const Role r)
2004-08-19 13:47:53 +01:00
{
int run;
if (p == INTRUDER)
2004-08-19 14:09:35 +01:00
num_intruder_runs++;
2004-08-19 13:47:53 +01:00
else
2004-08-19 14:09:35 +01:00
num_regular_runs++;
2004-08-19 13:47:53 +01:00
roleInstance (sys, p, r, NULL, NULL);
2004-08-19 15:49:03 +01:00
run = sys->maxruns-1;
2004-08-19 13:47:53 +01:00
sys->runs[run].length = 0;
return run;
}
//! Wrapper for roleDestroy
2004-08-19 14:09:35 +01:00
void
semiRunDestroy ()
2004-08-19 13:47:53 +01:00
{
2004-08-19 15:49:03 +01:00
if (sys->maxruns > 0)
{
Protocol p;
2004-08-19 13:47:53 +01:00
2004-08-19 15:49:03 +01:00
p = sys->runs[sys->maxruns - 1].protocol;
roleInstanceDestroy (sys);
if (p == INTRUDER)
num_intruder_runs--;
else
num_regular_runs--;
}
2004-08-19 13:47:53 +01:00
}
2004-08-17 16:52:52 +01:00
//! After a role instance, or an extension of a run, we might need to add some goals
/**
* From old to new. Sets the new length to new.
*@returns The number of goals added (for destructions)
*/
int
add_read_goals (const int run, const int old, const int new)
2004-08-17 16:52:52 +01:00
{
int count;
int i;
Roledef rd;
sys->runs[run].length = new;
i = old;
rd = roledef_shift (sys->runs[run].start, i);
count = 0;
while (i < new && rd != NULL)
2004-08-17 16:52:52 +01:00
{
if (rd->type == READ)
{
if (sys->output == PROOF)
{
if (count == 0)
{
2004-08-19 12:37:41 +01:00
indentPrint ();
eprintf ("Thus, we must also produce ");
}
else
{
eprintf (", ");
}
termPrint (rd->message);
2004-08-19 12:37:41 +01:00
}
2004-08-17 16:52:52 +01:00
goal_add (rd->message, run, i);
count++;
2004-08-17 16:52:52 +01:00
}
rd = rd->next;
i++;
}
if ((count > 0) && sys->output == PROOF)
{
eprintf ("\n");
}
2004-08-17 16:52:52 +01:00
return count;
}
//! Remove n goals
void
remove_read_goals (int n)
{
while (n > 0)
2004-08-17 16:52:52 +01:00
{
goal_remove_last ();
n--;
}
}
//! Determine the run that follows from a substitution.
/**
* After an Arachne unification, stuff might go wrong w.r.t. nonce instantiation.
* This function determines the run that is implied by a substitution list.
* @returns >= 0: a run, -1 for invalid, -2 for any run.
*/
int
determine_unification_run (Termlist tl)
{
int run;
run = -2;
while (tl != NULL)
{
//! Again, hardcoded reference to compiler.c. Level -3 means a local constant for a role.
if (tl->term->type != VARIABLE && tl->term->right.runid == -3)
{
Term t;
t = tl->term->subst;
// It is required that it is actually a leaf, because we construct it.
if (!realTermLeaf (t))
{
return -1;
}
else
{
if (run == -2)
{
// Any run
run = t->right.runid;
}
else
{
// Specific run: compare
if (run != t->right.runid)
{
return -1;
}
}
}
}
tl = tl->next;
}
return run;
}
//------------------------------------------------------------------------
// Proof reporting
//------------------------------------------------------------------------
//! Protocol/role name of a run
void
role_name_print (const int run)
{
eprintf ("protocol ");
termPrint (sys->runs[run].protocol->nameterm);
eprintf (", role ");
termPrint (sys->runs[run].role->nameterm);
}
//! Adding a run/extending a run
void
proof_suppose_run (const int run, const int oldlength, const int newlength)
{
if (sys->output == PROOF)
{
int reallength;
indentPrint ();
eprintf ("Suppose ");
if (oldlength == 0)
eprintf ("there is a ");
else
eprintf ("we extend ");
reallength = roledef_length (sys->runs[run].start);
if (reallength > newlength)
eprintf ("semi-");
eprintf ("run #%i of ", run);
role_name_print (run);
if (reallength > newlength)
{
if (oldlength == 0)
eprintf (" of");
else
eprintf (" to");
eprintf (" length %i", newlength);
}
eprintf ("\n");
}
}
//! Select a goal
void
proof_select_goal (Binding b)
{
if (sys->output == PROOF)
{
Roledef rd;
rd = roledef_shift (sys->runs[b->run_to].start, b->ev_to);
indentPrint ();
2004-08-19 12:37:41 +01:00
eprintf ("Selected goal: Where does term ");
termPrint (b->term);
2004-08-19 12:37:41 +01:00
eprintf (" originate first?\n");
indentPrint ();
eprintf ("* It is required for ");
roledefPrint (rd);
2004-08-19 12:37:41 +01:00
eprintf (" at index %i in run %i\n", b->ev_to, b->run_to);
}
}
//! Cannot bind because of cycle
void
proof_cannot_bind (const Binding b, const int run, const int index)
{
if (sys->output == PROOF)
{
indentPrint ();
eprintf
("Cannot bind this to run %i, index %i because that introduces a cycle.\n",
run, index);
}
}
//! Test a binding
void
proof_suppose_binding (Binding b)
{
if (sys->output == PROOF)
{
Roledef rd;
indentPrint ();
rd = roledef_shift (sys->runs[b->run_from].start, b->ev_from);
2004-08-19 12:37:41 +01:00
eprintf ("Suppose it originates in run %i, at index %i\n", b->run_from,
b->ev_from);
indentPrint ();
eprintf ("* I.e. event ");
roledefPrint (rd);
2004-08-19 12:37:41 +01:00
eprintf ("\n");
indentPrint ();
eprintf ("* from ");
role_name_print (b->run_from);
2004-08-19 12:37:41 +01:00
eprintf ("\n");
}
}
2004-08-11 13:08:10 +01:00
//------------------------------------------------------------------------
// Sub
//------------------------------------------------------------------------
//! Iterate over all send types in the roles (including the intruder ones)
/**
* Function is called with (protocol pointer, role pointer, roledef pointer, index)
* and returns an integer. If it is false, iteration aborts.
*/
int
iterate_role_sends (int (*func) ())
{
Protocol p;
p = sys->protocols;
while (p != NULL)
{
Role r;
r = p->roles;
while (r != NULL)
{
Roledef rd;
int index;
rd = r->roledef;
index = 0;
while (rd != NULL)
{
if (rd->type == SEND)
{
if (!func (p, r, rd, index))
return 0;
}
index++;
rd = rd->next;
}
r = r->next;
}
p = p->next;
}
return 1;
}
//! Try to bind a specific existing run to a goal.
/**
* The key goals are bound to the goal.
*@param subterm determines whether it is a subterm unification or not.
*/
int
2004-08-18 20:43:58 +01:00
bind_existing_to_goal (const Binding b, const int run, const int index)
{
Roledef rd;
int flag;
int old_length;
int newgoals;
int found;
int subterm_iterate (Termlist substlist, Termlist keylist)
{
int flag;
found++;
flag = 1;
if (goal_bind (b, run, index))
{
int keycount;
Termlist tl;
proof_suppose_binding (b);
if (keylist != NULL && sys->output == PROOF)
{
indentPrint ();
2004-08-19 12:37:41 +01:00
eprintf
("This introduces the obligation to produce the following keys: ");
termlistPrint (keylist);
eprintf ("\n");
}
keycount = 0;
tl = keylist;
while (tl != NULL)
{
int keyrun;
goal_add (tl->term, b->run_to, b->ev_to);
tl = tl->next;
keycount++;
}
indentDepth++;
flag = flag && iterate ();
indentDepth--;
while (keycount > 0)
{
goal_remove_last ();
keycount--;
}
}
else
{
2004-08-19 12:37:41 +01:00
proof_cannot_bind (b, run, index);
}
goal_unbind (b);
return flag;
}
//----------------------------
// Roledef entry
rd = roledef_shift (sys->runs[run].start, index);
// Fix length
old_length = sys->runs[run].length;
if ((index + 1) > old_length)
newgoals = add_read_goals (run, old_length, index + 1);
else
newgoals = 0;
// Bind to existing run
found = 0;
flag = termMguSubTerm (b->term, rd->message,
subterm_iterate, sys->know->inverses, NULL);
// Did it work?
if (found == 0 && sys->output == PROOF)
{
indentPrint ();
eprintf ("Cannot bind ");
termPrint (b->term);
2004-08-19 14:09:35 +01:00
eprintf (" to run %i, index %i because it does not subterm-unify.\n",
run, index);
}
// Reset length
remove_read_goals (newgoals);
sys->runs[run].length = old_length;
return flag;
}
//! Bind a goal to an existing regular run, if possible
int
bind_existing_run (const Binding b, const Protocol p, const Role r,
2004-08-18 20:43:58 +01:00
const int index)
{
int run, flag;
2004-08-19 12:37:41 +01:00
int found;
flag = 1;
2004-08-19 12:37:41 +01:00
found = 0;
for (run = 0; run < sys->maxruns; run++)
{
if (sys->runs[run].protocol == p && sys->runs[run].role == r)
{
2004-08-19 12:37:41 +01:00
found++;
if (sys->output == PROOF)
{
if (found == 1)
{
indentPrint ();
eprintf ("Can we bind it to an existing regular run of ");
termPrint (p->nameterm);
eprintf (", ");
termPrint (r->nameterm);
eprintf ("?\n");
}
indentPrint ();
eprintf ("%i. Can we bind it to run %i?\n", found, run);
}
indentDepth++;
2004-08-18 20:43:58 +01:00
flag = flag && bind_existing_to_goal (b, run, index);
2004-08-19 12:37:41 +01:00
indentDepth--;
}
}
2004-08-19 12:37:41 +01:00
if (sys->output == PROOF && found == 0)
{
indentPrint ();
eprintf ("There is no existing run for ");
termPrint (p->nameterm);
eprintf (", ");
termPrint (r->nameterm);
eprintf ("\n");
}
return flag;
}
//! Bind a goal to a new run
int
bind_new_run (const Binding b, const Protocol p, const Role r,
2004-08-18 20:43:58 +01:00
const int index)
{
2004-08-11 16:05:13 +01:00
int run;
int flag;
int newgoals;
2004-08-11 16:05:13 +01:00
2004-08-19 13:47:53 +01:00
run = semiRunCreate (p, r);
2004-08-19 12:37:41 +01:00
proof_suppose_run (run, 0, index + 1);
newgoals = add_read_goals (run, 0, index + 1);
2004-08-19 12:37:41 +01:00
indentDepth++;
2004-08-18 20:43:58 +01:00
flag = bind_existing_to_goal (b, run, index);
2004-08-19 12:37:41 +01:00
indentDepth--;
remove_read_goals (newgoals);
2004-08-19 13:47:53 +01:00
semiRunDestroy ();
2004-08-11 16:05:13 +01:00
return flag;
}
//! Print the current semistate
void
printSemiState ()
{
int run;
2004-08-14 15:38:30 +01:00
int open;
List bl;
int binding_state_print (void *dt)
{
binding_indent_print ((Binding) dt, 1);
return 1;
}
2004-08-14 15:38:30 +01:00
indentPrint ();
eprintf ("!! --=[ Semistate ]=--\n");
open = 0;
for (run = 0; run < sys->maxruns; run++)
{
int index;
2004-08-15 18:16:13 +01:00
Role r;
Roledef rd;
2004-08-15 18:16:13 +01:00
Term oldagent;
2004-08-15 18:16:13 +01:00
indentPrint ();
eprintf ("!!\n");
indentPrint ();
2004-08-14 15:38:30 +01:00
eprintf ("!! [ Run %i, ", run);
2004-08-15 18:16:13 +01:00
termPrint (sys->runs[run].protocol->nameterm);
eprintf (", ");
r = sys->runs[run].role;
oldagent = r->nameterm->subst;
r->nameterm->subst = NULL;
termPrint (r->nameterm);
r->nameterm->subst = oldagent;
if (oldagent != NULL)
{
eprintf (": ");
termPrint (oldagent);
}
eprintf (" ]\n");
index = 0;
rd = sys->runs[run].start;
while (index < sys->runs[run].length)
{
indentPrint ();
2004-08-14 15:38:30 +01:00
eprintf ("!! %i ", index);
roledefPrint (rd);
eprintf ("\n");
2004-08-14 15:38:30 +01:00
if (isGoal (rd) && !isBound (rd))
open++;
index++;
rd = rd->next;
}
}
if (sys->bindings != NULL)
{
indentPrint ();
eprintf ("!!\n");
list_iterate (sys->bindings, binding_state_print);
}
2004-08-14 15:38:30 +01:00
indentPrint ();
2004-08-15 18:16:13 +01:00
eprintf ("!!\n");
indentPrint ();
2004-08-14 15:38:30 +01:00
eprintf ("!! - open: %i -\n", open);
}
//------------------------------------------------------------------------
// Larger logical componentents
//------------------------------------------------------------------------
//! Goal selection
/**
* Should be ordered to prefer most constrained; for now, it is simply the first one encountered.
*/
Binding
select_goal ()
{
List bl;
Binding best;
float min_constrain;
min_constrain = 2; // 1 is the maximum, but we want to initialize it.
best = NULL;
bl = sys->bindings;
while (bl != NULL)
{
Binding b;
b = (Binding) bl->data;
if (!b->done)
{
// We don't care about singular agent variables, so...
2004-08-18 20:43:58 +01:00
if (!
(isTermVariable (b->term)
&& inTermlist (b->term->stype, TERM_Agent)))
{
float cons;
cons = term_constrain_level (b->term);
if (cons < min_constrain)
{
min_constrain = cons;
best = b;
}
}
}
bl = bl->next;
}
return best;
}
2004-08-18 19:22:59 +01:00
//! Create a new intruder run to generate knowledge from m0
int
bind_goal_new_m0 (const Binding b)
{
Termlist m0tl;
int flag;
int found;
2004-08-18 19:22:59 +01:00
flag = 1;
found = 0;
2004-08-18 19:22:59 +01:00
m0tl = knowledgeSet (sys->know);
while (flag && m0tl != NULL)
{
Term m0t;
Termlist subst;
m0t = m0tl->term;
subst = termMguTerm (b->term, m0t);
if (subst != MGUFAIL)
{
int run;
2004-08-19 13:47:53 +01:00
run = semiRunCreate (INTRUDER, I_M);
2004-08-19 12:37:41 +01:00
proof_suppose_run (run, 0, 1);
2004-08-18 19:22:59 +01:00
sys->runs[run].start->message = termDuplicate (b->term);
sys->runs[run].length = 1;
2004-08-19 12:37:41 +01:00
indentDepth++;
2004-08-18 19:22:59 +01:00
if (goal_bind (b, run, 0))
{
found++;
proof_suppose_binding (b);
if (sys->output == PROOF)
2004-08-18 19:22:59 +01:00
{
indentPrint ();
eprintf ("* I.e. retrieving ");
2004-08-18 19:22:59 +01:00
termPrint (b->term);
eprintf (" from the initial knowledge.\n");
}
flag = flag && iterate ();
}
2004-08-19 12:37:41 +01:00
else
{
proof_cannot_bind (b, run, 0);
}
2004-08-18 19:22:59 +01:00
goal_unbind (b);
2004-08-19 12:37:41 +01:00
indentDepth--;
2004-08-19 13:47:53 +01:00
semiRunDestroy ();
2004-08-19 15:49:03 +01:00
2004-08-18 19:22:59 +01:00
termlistSubstReset (subst);
termlistDelete (subst);
}
m0tl = m0tl->next;
}
if (found == 0 && sys->output == PROOF)
{
indentPrint ();
eprintf ("Term ");
termPrint (b->term);
eprintf (" cannot be constructed from the initial knowledge.\n");
}
2004-08-18 19:22:59 +01:00
termlistDelete (m0tl);
return flag;
}
//! Bind an intruder goal by intruder composition construction
/**
* Handles the case where the intruder constructs a composed term himself.
*/
2004-08-13 11:25:23 +01:00
int
2004-08-18 19:22:59 +01:00
bind_goal_new_encrypt (const Binding b)
2004-08-13 11:25:23 +01:00
{
Term term;
int flag;
2004-08-19 15:49:03 +01:00
int can_be_encrypted;
flag = 1;
2004-08-19 15:49:03 +01:00
term = deVar(b->term);
can_be_encrypted = 0;
2004-08-18 19:22:59 +01:00
if (!realTermLeaf (term))
{
int run;
int index;
int newgoals;
Roledef rd;
Term t1, t2;
2004-08-19 15:49:03 +01:00
if (!realTermEncrypt (term))
{
// tuple construction
error ("Goal that is a tuple should not occur!");
}
// must be encryption
t1 = term->left.op;
t2 = term->right.key;
2004-08-19 15:49:03 +01:00
if (t2 != TERM_Hidden)
{
2004-08-19 15:49:03 +01:00
can_be_encrypted = 1;
run = semiRunCreate (INTRUDER, I_RRS);
rd = sys->runs[run].start;
rd->message = termDuplicateUV (t1);
rd->next->message = termDuplicateUV (t2);
2004-08-19 15:49:03 +01:00
rd->next->next->message = termDuplicateUV (term);
index = 2;
proof_suppose_run (run, 0, index + 1);
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("* Encrypting ");
termPrint (term);
eprintf (" using term ");
termPrint (t1);
eprintf (" and key ");
termPrint (t2);
eprintf ("\n");
}
newgoals = add_read_goals (run, 0, index + 1);
indentDepth++;
if (goal_bind (b, run, index))
{
proof_suppose_binding (b);
flag = flag && iterate ();
}
else
{
proof_cannot_bind (b, run, index);
}
goal_unbind (b);
indentDepth--;
remove_read_goals (newgoals);
semiRunDestroy ();
2004-08-19 12:37:41 +01:00
}
}
2004-08-19 15:49:03 +01:00
if (!can_be_encrypted)
{
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Term ");
termPrint (b->term);
eprintf (" cannot be constructed by encryption.\n");
}
}
return flag;
2004-08-13 11:25:23 +01:00
}
2004-08-18 19:22:59 +01:00
//! Bind an intruder goal by intruder construction
/**
* Handles the case where the intruder constructs a composed term himself.
*/
int
bind_goal_new_intruder_run (const Binding b)
{
int flag;
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Can we bind ");
termPrint (b->term);
eprintf (" from a new intruder run?\n");
}
indentDepth++;
flag = bind_goal_new_m0 (b);
flag = flag && bind_goal_new_encrypt (b);
indentDepth--;
return flag;
2004-08-18 19:22:59 +01:00
}
2004-08-13 11:25:23 +01:00
//! Bind a regular goal
2004-08-11 13:08:10 +01:00
int
bind_goal_regular_run (const Binding b)
2004-08-11 13:08:10 +01:00
{
2004-08-15 18:07:38 +01:00
int flag;
2004-08-19 12:37:41 +01:00
int found;
2004-08-15 18:07:38 +01:00
/*
* This is a local function so we have access to goal
*/
int bind_this_role_send (Protocol p, Role r, Roledef rd, int index)
{
int test_unification (Termlist substlist)
2004-08-15 18:07:38 +01:00
{
// A unification exists; return the signal
return 0;
}
2004-08-15 18:07:38 +01:00
if (p == INTRUDER)
{
// No intruder roles here
return 1;
}
// Test for interm unification
#ifdef DEBUG
if (DEBUGL (5))
{
indentPrint ();
eprintf ("Checking send candidate with message ");
termPrint (rd->message);
eprintf (" from ");
termPrint (p->nameterm);
eprintf (", ");
termPrint (r->nameterm);
eprintf (", index %i\n", index);
}
#endif
if (!termMguSubTerm
(b->term, rd->message, test_unification, sys->know->inverses, NULL))
{
int flag;
// A good candidate
2004-08-19 12:37:41 +01:00
found++;
if (sys->output == PROOF && found == 1)
{
indentPrint ();
eprintf ("The term ", found);
termPrint (b->term);
2004-08-19 14:09:35 +01:00
eprintf
(" matches patterns from the role definitions. Investigate.\n");
}
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("%i. It matches the pattern ", found);
2004-08-19 12:37:41 +01:00
termPrint (rd->message);
eprintf (" from ");
termPrint (p->nameterm);
eprintf (", ");
termPrint (r->nameterm);
2004-08-19 12:37:41 +01:00
eprintf (", at %i\n", index);
}
indentDepth++;
// Bind to existing run
2004-08-18 20:43:58 +01:00
flag = bind_existing_run (b, p, r, index);
// bind to new run
2004-08-18 20:43:58 +01:00
flag = flag && bind_new_run (b, p, r, index);
indentDepth--;
return flag;
}
else
{
return 1;
}
}
// Bind to all possible sends of regular runs
2004-08-19 12:37:41 +01:00
found = 0;
flag = iterate_role_sends (bind_this_role_send);
if (sys->output == PROOF && found == 0)
{
indentPrint ();
eprintf ("The term ");
termPrint (b->term);
eprintf (" does not match any pattern from the role definitions.\n");
}
return flag;
}
// Bind to all possible sends of intruder runs
2004-08-18 20:43:58 +01:00
int
bind_goal_old_intruder_run (Binding b)
{
int run;
int flag;
int found;
found = 0;
flag = 1;
for (run = 0; run < sys->maxruns; run++)
{
if (sys->runs[run].protocol == INTRUDER)
{
int ev;
Roledef rd;
2004-08-18 20:43:58 +01:00
rd = sys->runs[run].start;
ev = 0;
while (ev < sys->runs[run].length)
{
if (rd->type == SEND)
{
found++;
if (sys->output == PROOF && found == 1)
{
indentPrint ();
2004-08-19 14:09:35 +01:00
eprintf
("Suppose it is from an existing intruder run.\n");
}
2004-08-19 14:09:35 +01:00
indentDepth++;
2004-08-18 20:43:58 +01:00
flag = flag && bind_existing_to_goal (b, run, ev);
2004-08-19 14:09:35 +01:00
indentDepth--;
}
rd = rd->next;
ev++;
}
}
}
if (sys->output == PROOF && found == 0)
{
indentPrint ();
eprintf ("No existing intruder runs to match to.\n");
}
return flag;
2004-08-11 13:08:10 +01:00
}
//! Bind a goal in all possible ways
int
bind_goal (const Binding b)
2004-08-11 13:08:10 +01:00
{
if (!b->done)
2004-08-11 13:08:10 +01:00
{
int flag;
proof_select_goal (b);
indentDepth++;
flag = bind_goal_regular_run (b);
flag = flag && bind_goal_old_intruder_run (b);
flag = flag && bind_goal_new_intruder_run (b);
indentDepth--;
return flag;
2004-08-11 13:08:10 +01:00
}
else
{
return 1;
2004-08-11 13:08:10 +01:00
}
}
2004-08-19 14:09:35 +01:00
//! Prune determination because of theorems
/**
2004-08-19 14:09:35 +01:00
*@returns true iff this state is invalid because of a theorem
*/
int
2004-08-19 14:09:35 +01:00
prune_theorems ()
{
Termlist tl;
2004-08-18 20:43:58 +01:00
List bl;
// Check if all agents are valid
tl = sys->runs[0].agents;
while (tl != NULL)
{
Term agent;
agent = deVar (tl->term);
if (!realTermLeaf (agent))
{
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Pruned because agent cannot be compound term.\n");
}
return 1;
}
if (!inTermlist (agent->stype, TERM_Agent))
{
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Pruned because agent must contain agent type.\n");
}
return 1;
}
if (!realTermVariable (agent) && inTermlist (sys->untrusted, agent))
{
if (sys->output == PROOF)
{
indentPrint ();
eprintf
("Pruned because all agents of the claim run must be trusted.\n");
}
return 1;
}
tl = tl->next;
}
// Check for c-minimality
if (!bindings_c_minimal ())
{
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Pruned because this is not <=c-minimal.\n");
}
return 1;
}
2004-08-18 20:43:58 +01:00
// Check for "Hidden" interm goals
bl = sys->bindings;
while (bl != NULL)
{
Binding b;
b = bl->data;
if (termInTerm (b->term, TERM_Hidden))
{
// Prune the state: we can never meet this
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Pruned because intruder can never construnct ");
termPrint (b->term);
eprintf ("\n");
}
2004-08-18 20:43:58 +01:00
return 1;
}
bl = bl->next;
}
return 0;
}
2004-08-19 14:09:35 +01:00
//! Prune determination for bounds
/**
*@returns true iff this state is invalid for some reason
*/
int
prune_bounds ()
{
Termlist tl;
List bl;
if (indentDepth > 20)
{
// Hardcoded limit on iterations
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Pruned because too many iteration levels.\n");
}
return 1;
}
if (num_regular_runs > sys->switchRuns)
{
// Hardcoded limit on runs
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Pruned because too many regular runs.\n");
}
return 1;
}
return 0;
}
//! Setup system for specific claim test
add_claim_specifics (const Claimlist cl, const Roledef rd)
{
if (cl->type == CLAIM_Secret)
{
/**
* Secrecy claim
*/
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("* To verify the secrecy claim, we add the term ");
termPrint (rd->message);
eprintf (" as a goal.\n");
indentPrint ();
2004-08-19 12:37:41 +01:00
eprintf
("* If all goals can be bound, this constitutes an attack.\n");
}
2004-08-19 14:09:35 +01:00
/**
* We say that a state exists for secrecy, but we don't really test wheter the claim can
* be reached (without reaching the attack).
*/
cl->count = statesIncrease (cl->count);
goal_add (rd->message, 0, cl->ev); // Assumption that all claims are in run 0
}
}
2004-08-18 21:22:33 +01:00
//! Count a false claim
void
count_false ()
{
current_claim->failed = statesIncrease (current_claim->failed);
}
2004-08-11 13:08:10 +01:00
//------------------------------------------------------------------------
// Main logic core
//------------------------------------------------------------------------
2004-08-18 21:22:33 +01:00
//! Check properties
int
property_check ()
{
int flag;
flag = 1;
if (current_claim->type == CLAIM_Secret)
{
// Secrecy claim
/**
* By the way the claim is handled, this automatically means a flaw.
*/
count_false ();
if (sys->output == ATTACK)
printSemiState ();
2004-08-18 21:22:33 +01:00
}
return flag;
}
2004-08-11 10:51:17 +01:00
//! Main recursive procedure for Arachne
int
iterate ()
{
int flag;
2004-08-11 13:08:10 +01:00
flag = 1;
2004-08-19 14:09:35 +01:00
if (!prune_theorems ())
{
2004-08-19 14:09:35 +01:00
if (!prune_bounds ())
{
Binding b;
2004-08-19 14:09:35 +01:00
/**
* Not pruned: count
*/
2004-08-11 13:08:10 +01:00
2004-08-19 14:09:35 +01:00
sys->states = statesIncrease (sys->states);
2004-08-19 14:09:35 +01:00
/**
* Check whether its a final state (i.e. all goals bound)
*/
2004-08-19 14:09:35 +01:00
b = select_goal ();
if (b == NULL)
{
2004-08-19 14:09:35 +01:00
/*
* all goals bound, check for property
*/
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("All goals are now bound.\n");
}
sys->claims = statesIncrease (sys->claims);
current_claim->count = statesIncrease (current_claim->count);
flag = property_check ();
}
else
{
/*
* bind this goal in all possible ways and iterate
*/
flag = bind_goal (b);
}
}
else
{
2004-08-19 14:09:35 +01:00
// Pruned because of bound!
current_claim->complete = 0;
}
2004-08-11 13:08:10 +01:00
}
2004-08-18 19:22:59 +01:00
#ifdef DEBUG
if (DEBUGL (5) && !flag)
2004-08-18 19:22:59 +01:00
{
warning ("Flag has turned 0!");
}
#endif
return flag;
}
//! Main code for Arachne
/**
* For this test, we manually set up some stuff.
*
* But later, this will just iterate over all claims.
*/
int
arachne ()
2004-08-11 10:51:17 +01:00
{
2004-08-14 16:59:14 +01:00
Claimlist cl;
int print_send (Protocol p, Role r, Roledef rd, int index)
{
eprintf ("IRS: ");
termPrint (p->nameterm);
eprintf (", ");
termPrint (r->nameterm);
eprintf (", %i, ", index);
roledefPrint (rd);
eprintf ("\n");
return 1;
}
int determine_encrypt_max (Protocol p, Role r, Roledef rd, int index)
{
int tlevel;
tlevel = term_encryption_level (rd->message);
if (tlevel > max_encryption_level)
max_encryption_level = tlevel;
return 1;
}
2004-08-19 13:47:53 +01:00
/*
* set up claim role(s)
*/
if (sys->maxruns > 0)
{
error ("Something is wrong, number of runs >0.");
}
num_regular_runs = 0;
num_intruder_runs = 0;
max_encryption_level = 0;
iterate_role_sends (determine_encrypt_max);
#ifdef DEBUG
if (DEBUGL (1))
{
eprintf ("Maximum encryption level: %i\n", max_encryption_level);
iterate_role_sends (print_send);
}
#endif
indentDepth = 0;
2004-08-14 16:59:14 +01:00
cl = sys->claimlist;
while (cl != NULL)
{
/**
* Check each claim
*/
2004-08-14 16:59:14 +01:00
Protocol p;
Role r;
if (sys->switchClaimToCheck == NULL
|| sys->switchClaimToCheck == cl->type)
{
2004-08-19 13:47:53 +01:00
int run;
current_claim = cl;
2004-08-19 14:09:35 +01:00
cl->complete = 1;
p = (Protocol) cl->protocol;
r = (Role) cl->role;
if (sys->output == PROOF)
{
indentPrint ();
eprintf ("Testing Claim ");
termPrint (cl->type);
eprintf (" from ");
termPrint (p->nameterm);
eprintf (", ");
termPrint (r->nameterm);
eprintf (" at index %i.\n", cl->ev);
}
indentDepth++;
2004-08-19 14:09:35 +01:00
run = semiRunCreate (p, r);
2004-08-19 13:47:53 +01:00
proof_suppose_run (run, 0, cl->ev + 1);
add_read_goals (run, 0, cl->ev + 1);
/**
* Add specific goal info
*/
add_claim_specifics (cl,
2004-08-19 13:47:53 +01:00
roledef_shift (sys->runs[run].start, cl->ev));
2004-08-14 16:59:14 +01:00
#ifdef DEBUG
if (DEBUGL (5))
{
printSemiState ();
}
2004-08-14 16:59:14 +01:00
#endif
2004-08-19 15:49:03 +01:00
// Iterate
iterate ();
2004-08-14 16:59:14 +01:00
//! Destroy
2004-08-19 15:49:03 +01:00
while (sys->bindings != NULL)
{
remove_read_goals (1);
}
while (sys->maxruns > 0)
{
2004-08-19 13:47:53 +01:00
semiRunDestroy ();
}
indentDepth--;
}
2004-08-14 16:59:14 +01:00
// next
cl = cl->next;
}
2004-08-11 10:51:17 +01:00
}