2004-08-11 10:51:17 +01:00
|
|
|
/**
|
2004-08-18 16:46:33 +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/
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
#include <stdlib.h>
|
2004-08-27 19:09:09 +01:00
|
|
|
#include <limits.h>
|
2004-12-29 14:17:49 +00:00
|
|
|
#include <float.h>
|
2004-12-08 16:25:27 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2004-08-11 13:08:10 +01:00
|
|
|
#include "term.h"
|
2004-08-11 15:09:12 +01:00
|
|
|
#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"
|
2004-08-15 17:44:54 +01:00
|
|
|
#include "knowledge.h"
|
2004-08-12 13:28:57 +01:00
|
|
|
#include "compiler.h"
|
2004-08-11 15:09:12 +01:00
|
|
|
#include "states.h"
|
|
|
|
#include "mgu.h"
|
2004-08-11 10:51:17 +01:00
|
|
|
#include "arachne.h"
|
2004-10-25 15:28:53 +01:00
|
|
|
#include "memory.h"
|
2004-08-14 16:59:14 +01:00
|
|
|
#include "error.h"
|
|
|
|
#include "claim.h"
|
2004-08-14 17:12:32 +01:00
|
|
|
#include "debug.h"
|
2004-08-15 13:24:27 +01:00
|
|
|
#include "binding.h"
|
2004-08-28 14:47:37 +01:00
|
|
|
#include "warshall.h"
|
2005-01-05 15:29:27 +00:00
|
|
|
#include "timer.h"
|
2005-06-02 13:14:28 +01:00
|
|
|
#include "type.h"
|
2005-06-07 16:02:27 +01:00
|
|
|
#include "switches.h"
|
2005-06-16 15:10:07 +01:00
|
|
|
#include "specialterm.h"
|
2005-12-27 11:19:45 +00:00
|
|
|
#include "cost.h"
|
2005-12-27 11:50:46 +00:00
|
|
|
#include "dotout.h"
|
2006-01-02 18:43:25 +00:00
|
|
|
#include "prune_bounds.h"
|
|
|
|
#include "prune_theorems.h"
|
2006-01-02 20:18:47 +00:00
|
|
|
#include "arachne.h"
|
2006-02-22 08:24:29 +00:00
|
|
|
#include "hidelevel.h"
|
2006-02-26 15:00:58 +00:00
|
|
|
#include "depend.h"
|
2004-08-14 20:19:23 +01:00
|
|
|
|
2004-08-28 14:47:37 +01:00
|
|
|
extern int *graph;
|
|
|
|
extern int nodes;
|
2004-12-08 16:25:27 +00:00
|
|
|
extern int graph_uordblks;
|
2004-08-28 14:47:37 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
static System sys; //!< local buffer for the system pointer
|
2006-01-02 18:43:25 +00:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
int attack_length; //!< length of the attack
|
|
|
|
int attack_leastcost; //!< cost of the best attack sofar \sa cost.c
|
2004-08-18 21:22:33 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
Protocol INTRUDER; //!< intruder protocol
|
|
|
|
Role I_M; //!< Initial knowledge role of the intruder
|
|
|
|
Role I_RRS; //!< Encrypt role of the intruder
|
|
|
|
Role I_RRSD; //!< Decrypt role of the intruder
|
2004-08-11 13:08:10 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
int proofDepth; //!< Current depth of the proof
|
|
|
|
int max_encryption_level; //!< Maximum encryption level of any term
|
|
|
|
int num_regular_runs; //!< Current number of regular runs
|
|
|
|
int num_intruder_runs; //!< Current number of intruder runs
|
2006-01-02 18:43:25 +00:00
|
|
|
|
2004-08-13 12:11:59 +01:00
|
|
|
static int indentDepth;
|
2005-05-19 15:43:32 +01:00
|
|
|
static int prevIndentDepth;
|
|
|
|
static int indentDepthChanges;
|
2005-12-27 10:49:22 +00:00
|
|
|
static FILE *attack_stream;
|
2004-08-13 12:11:59 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
/*
|
2004-08-11 15:09:12 +01:00
|
|
|
* Forward declarations
|
|
|
|
*/
|
|
|
|
|
|
|
|
int iterate ();
|
2004-10-18 14:04:34 +01:00
|
|
|
void printSemiState ();
|
2004-08-11 15:09:12 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
/*
|
2004-08-11 15:09:12 +01:00
|
|
|
* Program code
|
|
|
|
*/
|
|
|
|
|
2004-08-11 12:22:20 +01:00
|
|
|
//! Init Arachne engine
|
|
|
|
void
|
2004-08-11 15:09:12 +01:00
|
|
|
arachneInit (const System mysys)
|
2004-08-11 12:22:20 +01:00
|
|
|
{
|
2004-12-08 19:30:26 +00:00
|
|
|
Roledef rd;
|
2004-08-15 17:44:54 +01:00
|
|
|
Termlist tl, know0;
|
2004-08-12 12:55:03 +01:00
|
|
|
|
|
|
|
void add_event (int event, Term message)
|
2004-08-12 13:28:57 +01:00
|
|
|
{
|
|
|
|
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;
|
2004-08-12 14:22:49 +01:00
|
|
|
// compute_role_variables (sys, INTRUDER, r);
|
2004-08-12 13:28:57 +01:00
|
|
|
return r;
|
|
|
|
}
|
2004-08-12 12:55:03 +01:00
|
|
|
|
2004-08-11 15:09:12 +01:00
|
|
|
sys = mysys; // make sys available for this module as a global
|
2004-08-14 15:23:21 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Very important: turn role terms that are local to a run, into variables.
|
|
|
|
*/
|
|
|
|
term_rolelocals_are_variables ();
|
|
|
|
|
2004-08-11 12:22:20 +01:00
|
|
|
/*
|
|
|
|
* Add intruder protocol roles
|
|
|
|
*/
|
2004-08-12 12:55:03 +01:00
|
|
|
|
|
|
|
INTRUDER = protocolCreate (makeGlobalConstant (" INTRUDER "));
|
|
|
|
|
2004-12-08 19:30:26 +00:00
|
|
|
// Initially empty roledef
|
|
|
|
rd = NULL;
|
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
add_event (SEND, NULL);
|
2004-08-17 12:30:03 +01:00
|
|
|
I_M = add_role ("I_M: Atomic message");
|
2004-08-12 12:55:03 +01:00
|
|
|
|
2004-08-17 12:30:03 +01:00
|
|
|
add_event (READ, NULL);
|
|
|
|
add_event (READ, NULL);
|
2004-08-16 15:49:41 +01:00
|
|
|
add_event (SEND, NULL);
|
2004-08-19 15:49:03 +01:00
|
|
|
I_RRS = add_role ("I_E: Encrypt");
|
2004-08-16 15:49:41 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
add_event (READ, NULL);
|
|
|
|
add_event (READ, NULL);
|
|
|
|
add_event (SEND, NULL);
|
|
|
|
I_RRSD = add_role ("I_D: Decrypt");
|
|
|
|
|
|
|
|
num_regular_runs = 0;
|
|
|
|
num_intruder_runs = 0;
|
|
|
|
max_encryption_level = 0;
|
|
|
|
|
2005-05-19 15:43:32 +01:00
|
|
|
indentDepth = 0;
|
|
|
|
prevIndentDepth = 0;
|
|
|
|
indentDepthChanges = 0;
|
|
|
|
|
2004-08-11 12:22:20 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Close Arachne engine
|
|
|
|
void
|
2004-08-11 15:09:12 +01:00
|
|
|
arachneDone ()
|
2004-08-11 12:22:20 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-08-11 13:08:10 +01:00
|
|
|
//------------------------------------------------------------------------
|
|
|
|
// Detail
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
//! Just a defined integer for invalid
|
2004-08-11 13:08:10 +01:00
|
|
|
#define INVALID -1
|
2006-01-02 21:06:08 +00:00
|
|
|
//! can this roledef constitute a read Goal?
|
2004-08-11 15:09:12 +01:00
|
|
|
#define isGoal(rd) (rd->type == READ && !rd->internal)
|
2006-01-02 21:06:08 +00:00
|
|
|
//! is this roledef already bound?
|
2004-08-15 13:24:27 +01:00
|
|
|
#define isBound(rd) (rd->bound)
|
2004-08-11 13:08:10 +01:00
|
|
|
|
2005-05-19 15:43:32 +01:00
|
|
|
//! Indent prefix print
|
2004-08-12 12:35:13 +01:00
|
|
|
void
|
2005-05-19 15:43:32 +01:00
|
|
|
indentPrefixPrint (const int annotate, const int jumps)
|
2004-08-12 12:35:13 +01:00
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == ATTACK && globalError == 0)
|
2004-08-19 11:46:27 +01:00
|
|
|
{
|
2004-10-18 14:04:34 +01:00
|
|
|
// Arachne, attack, not an error
|
|
|
|
// We assume that means DOT output
|
2005-05-19 15:43:32 +01:00
|
|
|
eprintf ("// %i\t", annotate);
|
2004-10-18 14:04:34 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If it is not to stdout, or it is not an attack...
|
|
|
|
int i;
|
|
|
|
|
2005-05-19 15:43:32 +01:00
|
|
|
eprintf ("%i\t", annotate);
|
|
|
|
for (i = 0; i < jumps; i++)
|
2004-10-18 14:04:34 +01:00
|
|
|
{
|
|
|
|
if (i % 3 == 0)
|
|
|
|
eprintf ("|");
|
|
|
|
else
|
|
|
|
eprintf (" ");
|
|
|
|
eprintf (" ");
|
|
|
|
}
|
2004-08-19 11:46:27 +01:00
|
|
|
}
|
2004-08-13 11:50:56 +01:00
|
|
|
}
|
2004-08-12 12:35:13 +01:00
|
|
|
|
2005-05-19 15:43:32 +01:00
|
|
|
//! Indent print
|
|
|
|
/**
|
|
|
|
* More subtle than before. Indentlevel changes now cause a counter to be increased, which is printed. Nice to find stuff in attacks.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
indentPrint ()
|
|
|
|
{
|
|
|
|
if (indentDepth != prevIndentDepth)
|
|
|
|
{
|
|
|
|
indentDepthChanges++;
|
|
|
|
while (indentDepth != prevIndentDepth)
|
|
|
|
{
|
|
|
|
if (prevIndentDepth < indentDepth)
|
|
|
|
{
|
|
|
|
indentPrefixPrint (indentDepthChanges, prevIndentDepth);
|
|
|
|
eprintf ("{\n");
|
|
|
|
prevIndentDepth++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prevIndentDepth--;
|
|
|
|
indentPrefixPrint (indentDepthChanges, prevIndentDepth);
|
|
|
|
eprintf ("}\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
indentPrefixPrint (indentDepthChanges, indentDepth);
|
|
|
|
}
|
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
//! Print indented binding
|
|
|
|
void
|
2004-08-20 12:47:00 +01:00
|
|
|
binding_indent_print (const Binding b, const int flag)
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
if (flag)
|
|
|
|
eprintf ("!! ");
|
|
|
|
binding_print (b);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
//! Keylevel tester: can this term ever be sent at this keylevel?
|
|
|
|
int
|
|
|
|
isKeylevelRight (Term t, const int kl)
|
|
|
|
{
|
|
|
|
t = deVar (t);
|
|
|
|
if (realTermLeaf (t))
|
|
|
|
{
|
|
|
|
// Leaf
|
|
|
|
if (isTermVariable (t))
|
|
|
|
{
|
|
|
|
// Variables are okay
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Constant, does it have a keylevel?
|
|
|
|
int mykl;
|
|
|
|
|
|
|
|
mykl = TermSymb (t)->keylevel;
|
|
|
|
if (mykl < INT_MAX)
|
|
|
|
{
|
|
|
|
// Sensible keylevel, so it must be possible
|
|
|
|
return (mykl <= kl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Never sent?
|
|
|
|
// So we can not expect it to come from that
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Node
|
|
|
|
if (realTermTuple (t))
|
|
|
|
{
|
|
|
|
// Tuple
|
|
|
|
return isKeylevelRight (TermOp1 (t), kl)
|
|
|
|
&& isKeylevelRight (TermOp2 (t), kl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Crypt
|
|
|
|
return isKeylevelRight (TermOp1 (t), kl)
|
|
|
|
&& isKeylevelRight (TermOp2 (t), kl + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Keylevel tester: can this term ever be sent at this keylevel?
|
|
|
|
/**
|
2006-02-22 09:53:50 +00:00
|
|
|
* Depends on the keylevel lemma (so this will not be called when those lemmas
|
|
|
|
* are disabled) and the keylevel constructors in symbol.c The idea is that
|
|
|
|
* certain terms will never be sent.
|
2005-03-08 13:02:16 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
isPossiblySent (Term t)
|
|
|
|
{
|
|
|
|
return isKeylevelRight (t, 0);
|
|
|
|
}
|
|
|
|
|
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++;
|
2006-02-26 17:18:59 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (5))
|
|
|
|
{
|
|
|
|
globalError++;
|
|
|
|
eprintf ("Adding a run %i with semiRunCreate, ", sys->maxruns);
|
|
|
|
termPrint (p->nameterm);
|
|
|
|
eprintf (", ");
|
|
|
|
termPrint (r->nameterm);
|
|
|
|
eprintf ("\n");
|
|
|
|
globalError--;
|
|
|
|
}
|
|
|
|
#endif
|
2004-08-19 13:47:53 +01:00
|
|
|
roleInstance (sys, p, r, NULL, NULL);
|
2004-08-19 15:55:21 +01:00
|
|
|
run = sys->maxruns - 1;
|
2006-01-02 21:06:08 +00:00
|
|
|
sys->runs[run].height = 0;
|
2004-08-19 13:47:53 +01:00
|
|
|
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-18 15:06:14 +01:00
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
//! Fix the keylevels of any agents
|
|
|
|
/**
|
|
|
|
* We simply extract the agent names from m0 (ugly hack)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fixAgentKeylevels (void)
|
|
|
|
{
|
|
|
|
Termlist tl, m0tl;
|
|
|
|
|
|
|
|
m0tl = knowledgeSet (sys->know);
|
|
|
|
tl = m0tl;
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
Term t;
|
|
|
|
|
|
|
|
t = deVar (tl->term);
|
|
|
|
if (realTermLeaf (t))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// a real agent type thing
|
|
|
|
if (TermSymb (t)->keylevel == INT_MAX)
|
|
|
|
{
|
|
|
|
// Fix the keylevel
|
|
|
|
TermSymb (t)->keylevel = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
termlistDelete (m0tl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
/**
|
2006-01-02 21:06:08 +00:00
|
|
|
* From old to new. Sets the new height to new.
|
2004-08-17 16:52:52 +01:00
|
|
|
*@returns The number of goals added (for destructions)
|
|
|
|
*/
|
|
|
|
int
|
2004-08-18 15:06:14 +01:00
|
|
|
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;
|
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
sys->runs[run].height = new;
|
2004-08-17 16:52:52 +01:00
|
|
|
i = old;
|
2004-08-18 10:57:01 +01:00
|
|
|
rd = roledef_shift (sys->runs[run].start, i);
|
2004-08-18 15:06:14 +01:00
|
|
|
count = 0;
|
|
|
|
while (i < new && rd != NULL)
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
|
|
|
if (rd->type == READ)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 11:46:27 +01:00
|
|
|
{
|
|
|
|
if (count == 0)
|
|
|
|
{
|
2004-08-19 12:37:41 +01:00
|
|
|
indentPrint ();
|
2004-08-19 13:35:51 +01:00
|
|
|
eprintf ("Thus, we must also produce ");
|
2004-08-19 11:46:27 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eprintf (", ");
|
|
|
|
}
|
|
|
|
termPrint (rd->message);
|
2004-08-19 12:37:41 +01:00
|
|
|
}
|
2004-10-18 14:04:34 +01:00
|
|
|
count = count + goal_add (rd->message, run, i, 0);
|
2004-08-17 16:52:52 +01:00
|
|
|
}
|
|
|
|
rd = rd->next;
|
|
|
|
i++;
|
|
|
|
}
|
2005-06-07 16:02:27 +01:00
|
|
|
if ((count > 0) && switches.output == PROOF)
|
2004-08-19 11:46:27 +01:00
|
|
|
{
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2004-08-14 15:23:21 +01:00
|
|
|
//! 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.
|
2004-11-16 12:07:55 +00:00
|
|
|
if (tl->term->type != VARIABLE && TermRunid (tl->term) == -3)
|
2004-08-14 15:23:21 +01:00
|
|
|
{
|
|
|
|
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
|
2004-11-16 12:07:55 +00:00
|
|
|
run = TermRunid (t);
|
2004-08-14 15:23:21 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Specific run: compare
|
2004-11-16 12:07:55 +00:00
|
|
|
if (run != TermRunid (t))
|
2004-08-14 15:23:21 +01:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
return run;
|
|
|
|
}
|
|
|
|
|
2004-08-27 19:09:09 +01:00
|
|
|
//! Determine trace length
|
|
|
|
int
|
2005-05-01 14:32:50 +01:00
|
|
|
get_semitrace_length ()
|
2004-08-27 19:09:09 +01:00
|
|
|
{
|
|
|
|
int run;
|
|
|
|
int length;
|
|
|
|
|
|
|
|
run = 0;
|
|
|
|
length = 0;
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
if (sys->runs[run].protocol != INTRUDER)
|
|
|
|
{
|
|
|
|
// Non-intruder run: count length
|
2004-08-27 20:15:24 +01:00
|
|
|
// Subtract 'firstReal' to ignore chooses.
|
2006-01-02 21:06:08 +00:00
|
|
|
length = length + sys->runs[run].height - sys->runs[run].firstReal;
|
2004-08-27 19:09:09 +01:00
|
|
|
}
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
2005-08-21 22:38:32 +01:00
|
|
|
//! Count intruder events
|
|
|
|
int
|
|
|
|
countIntruderActions ()
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
int run;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
run = 0;
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
if (sys->runs[run].protocol == INTRUDER)
|
|
|
|
{
|
|
|
|
// Only intruder roles
|
|
|
|
if (sys->runs[run].role != I_M)
|
|
|
|
{
|
|
|
|
// The M_0 (initial knowledge) events don't count.
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2004-08-19 11:46:27 +01:00
|
|
|
//------------------------------------------------------------------------
|
|
|
|
// 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)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 11:46:27 +01:00
|
|
|
{
|
|
|
|
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");
|
2004-08-19 15:52:17 +01:00
|
|
|
eprintf (" length %i", newlength);
|
2004-08-19 11:46:27 +01:00
|
|
|
}
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Select a goal
|
|
|
|
void
|
|
|
|
proof_select_goal (Binding b)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 11:46:27 +01:00
|
|
|
{
|
|
|
|
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 ");
|
2004-08-19 11:46:27 +01:00
|
|
|
termPrint (b->term);
|
2004-08-19 15:55:21 +01:00
|
|
|
eprintf (" occur first as an interm?\n");
|
2004-08-19 12:37:41 +01:00
|
|
|
indentPrint ();
|
|
|
|
eprintf ("* It is required for ");
|
2004-08-19 11:46:27 +01:00
|
|
|
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)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 12:37:41 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("Cannot bind this to run %i, index %i because that introduces a cycle.\n",
|
|
|
|
run, index);
|
2004-08-19 11:46:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Test a binding
|
|
|
|
void
|
|
|
|
proof_suppose_binding (Binding b)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 11:46:27 +01:00
|
|
|
{
|
|
|
|
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 ");
|
2004-08-19 11:46:27 +01:00
|
|
|
roledefPrint (rd);
|
2004-08-19 12:37:41 +01:00
|
|
|
eprintf ("\n");
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("* from ");
|
2004-08-19 11:46:27 +01:00
|
|
|
role_name_print (b->run_from);
|
2004-08-19 12:37:41 +01:00
|
|
|
eprintf ("\n");
|
2004-08-19 11:46:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-27 10:49:22 +00:00
|
|
|
//! Create a new temporary file and return the pointer.
|
|
|
|
FILE *
|
|
|
|
scyther_tempfile (void)
|
|
|
|
{
|
|
|
|
return tmpfile ();
|
|
|
|
}
|
|
|
|
|
2004-08-11 13:08:10 +01:00
|
|
|
//------------------------------------------------------------------------
|
|
|
|
// Sub
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
2005-04-18 06:51:25 +01:00
|
|
|
//! Iterate over all events in the roles (including the intruder ones)
|
2004-08-11 15:09:12 +01:00
|
|
|
/**
|
|
|
|
* Function is called with (protocol pointer, role pointer, roledef pointer, index)
|
|
|
|
* and returns an integer. If it is false, iteration aborts.
|
|
|
|
*/
|
|
|
|
int
|
2005-04-18 06:51:25 +01:00
|
|
|
iterate_role_events (int (*func) ())
|
2004-08-11 15:09:12 +01:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2005-04-18 06:51:25 +01:00
|
|
|
if (!func (p, r, rd, index))
|
|
|
|
return 0;
|
2004-08-11 15:09:12 +01:00
|
|
|
index++;
|
|
|
|
rd = rd->next;
|
|
|
|
}
|
|
|
|
r = r->next;
|
|
|
|
}
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-04-18 06:51:25 +01:00
|
|
|
//! 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) ())
|
|
|
|
{
|
|
|
|
int send_wrapper (Protocol p, Role r, Roledef rd, int i)
|
2005-05-01 14:32:50 +01:00
|
|
|
{
|
|
|
|
if (rd->type == SEND)
|
|
|
|
{
|
|
|
|
return func (p, r, rd, i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2005-04-18 06:51:25 +01:00
|
|
|
|
|
|
|
return iterate_role_events (send_wrapper);
|
|
|
|
}
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
//! Create decryption role instance
|
|
|
|
/**
|
|
|
|
* Note that this does not add any bindings for the reads.
|
|
|
|
*
|
|
|
|
*@param term The term to be decrypted (implies decryption key)
|
2006-01-02 21:06:08 +00:00
|
|
|
*@param key The key that is needed to decrypt the term
|
2005-05-17 19:45:01 +01:00
|
|
|
*
|
|
|
|
*@returns The run id of the decryptor instance
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
create_decryptor (const Term term, const Term key)
|
|
|
|
{
|
|
|
|
if (term != NULL && isTermEncrypt (term))
|
|
|
|
{
|
|
|
|
Roledef rd;
|
|
|
|
Term tempkey;
|
|
|
|
int run;
|
|
|
|
|
2006-02-26 17:18:59 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (5))
|
|
|
|
{
|
|
|
|
globalError++;
|
|
|
|
eprintf ("Creating decryptor for term ");
|
|
|
|
termPrint (term);
|
|
|
|
eprintf (" and key ");
|
|
|
|
termPrint (key);
|
|
|
|
eprintf ("\n");
|
|
|
|
globalError--;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
run = semiRunCreate (INTRUDER, I_RRSD);
|
|
|
|
rd = sys->runs[run].start;
|
|
|
|
rd->message = termDuplicateUV (term);
|
|
|
|
rd->next->message = termDuplicateUV (key);
|
|
|
|
rd->next->next->message = termDuplicateUV (TermOp (term));
|
2006-01-02 21:06:08 +00:00
|
|
|
sys->runs[run].height = 3;
|
2005-05-17 19:45:01 +01:00
|
|
|
proof_suppose_run (run, 0, 3);
|
|
|
|
|
|
|
|
return run;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
globalError++;
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf ("Term for which a decryptor instance is requested: ");
|
2005-05-17 19:45:01 +01:00
|
|
|
termPrint (term);
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf ("\n");
|
2005-05-17 19:45:01 +01:00
|
|
|
error
|
|
|
|
("Trying to build a decryptor instance for a non-encrypted term.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Get the priority level of a key that is needed for a term (typical pk/sk distinction)
|
|
|
|
int
|
|
|
|
getPriorityOfNeededKey (const System sys, const Term keyneeded)
|
|
|
|
{
|
|
|
|
int prioritylevel;
|
|
|
|
|
|
|
|
/* Normally, a key gets higher priority, but unfortunately this is not propagated at the moment. Maybe later.
|
|
|
|
*/
|
|
|
|
prioritylevel = 1;
|
|
|
|
if (realTermEncrypt (keyneeded))
|
|
|
|
{
|
|
|
|
/* the key is a construction itself */
|
|
|
|
if (inKnowledge (sys->know, TermKey (keyneeded)))
|
|
|
|
{
|
|
|
|
/* the key is constructed by a public thing */
|
|
|
|
/* typically, this is a public key, so we postpone it */
|
|
|
|
prioritylevel = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return prioritylevel;
|
|
|
|
}
|
|
|
|
|
2006-02-26 17:18:59 +00:00
|
|
|
//! Try to bind a specific existing run to a goal.
|
|
|
|
/**
|
|
|
|
* The idea is that we try to bind it this specific run and index. If this
|
|
|
|
* requires keys, then we should add such goals as well with the required
|
|
|
|
* decryptor things.
|
|
|
|
*
|
|
|
|
* The key goals are bound to the goal. Iterates on success.
|
|
|
|
*/
|
2006-02-26 20:01:22 +00:00
|
|
|
void
|
2006-02-26 17:18:59 +00:00
|
|
|
bind_existing_to_goal (const Binding b, const int run, const int index)
|
|
|
|
{
|
|
|
|
int old_length;
|
|
|
|
int newgoals;
|
2006-02-26 20:01:22 +00:00
|
|
|
Term goalterm;
|
2006-02-26 17:18:59 +00:00
|
|
|
|
2006-02-26 20:01:22 +00:00
|
|
|
int subterm_unification_needs (Term tbig, const int r, const int e)
|
2006-02-26 17:18:59 +00:00
|
|
|
{
|
|
|
|
Term t;
|
|
|
|
|
2006-02-26 20:01:22 +00:00
|
|
|
void bind_iterate (Termlist tl)
|
2006-02-26 17:18:59 +00:00
|
|
|
{
|
2006-02-26 20:01:22 +00:00
|
|
|
if (goal_bind (b, r, e))
|
2006-02-26 17:18:59 +00:00
|
|
|
{
|
2006-02-26 20:01:22 +00:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Iterating for ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf (" to occur first in ");
|
|
|
|
termPrint (roledef_shift (sys->runs[run].start, index)->
|
|
|
|
message);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
iterate ();
|
|
|
|
goal_unbind (b);
|
2006-02-26 17:18:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-26 20:01:22 +00:00
|
|
|
t = deVar (b->term);
|
2006-02-26 17:18:59 +00:00
|
|
|
tbig = deVar (tbig);
|
|
|
|
|
|
|
|
// First check whether it unifies in a simple way
|
2006-02-26 20:01:22 +00:00
|
|
|
unify (t, tbig, NULL, bind_iterate);
|
2006-02-26 17:18:59 +00:00
|
|
|
|
|
|
|
// The other options are unification on subparts
|
|
|
|
if (realTermTuple (tbig))
|
|
|
|
{
|
|
|
|
// Either one will do
|
2006-02-26 20:01:22 +00:00
|
|
|
subterm_unification_needs (TermOp1 (tbig), r, e);
|
|
|
|
subterm_unification_needs (TermOp1 (tbig), r, e);
|
2006-02-26 17:18:59 +00:00
|
|
|
}
|
|
|
|
if (realTermEncrypt (tbig))
|
|
|
|
{
|
|
|
|
Term keyneeded;
|
|
|
|
Roledef rddecrypt;
|
|
|
|
int smallrun;
|
|
|
|
int prioritylevel;
|
|
|
|
int newgoals;
|
|
|
|
Binding bnew;
|
|
|
|
|
2006-02-26 20:01:22 +00:00
|
|
|
indentDepth++;
|
2006-02-26 17:18:59 +00:00
|
|
|
// Maybe we can bind to the inner thing. Try.
|
|
|
|
// Add decryptor run
|
|
|
|
keyneeded = inverseKey (sys->know->inverses, TermKey (tbig));
|
|
|
|
prioritylevel = getPriorityOfNeededKey (sys, keyneeded);
|
|
|
|
smallrun = create_decryptor (tbig, keyneeded);
|
|
|
|
rddecrypt = sys->runs[smallrun].start;
|
|
|
|
|
2006-02-26 20:01:22 +00:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("This introduces the obligation to decrypt the following subterm: ");
|
|
|
|
termPrint (tbig);
|
|
|
|
eprintf (" to be decrypted using ");
|
|
|
|
termPrint (keyneeded);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
|
2006-02-26 17:18:59 +00:00
|
|
|
/*
|
|
|
|
* 2. Add goal bindings
|
|
|
|
*/
|
|
|
|
|
|
|
|
newgoals = goal_add (rddecrypt->message, smallrun, 0, 0);
|
|
|
|
if (newgoals >= 0)
|
|
|
|
{
|
|
|
|
if (newgoals > 1)
|
|
|
|
{
|
|
|
|
error
|
|
|
|
("Added more than one goal for decryptor goal 1, weird.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This is the unique new goal then
|
|
|
|
bnew = (Binding) sys->bindings->data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error ("No new binding added for inner message.");
|
|
|
|
// No new binding? Weird, but fair enough
|
|
|
|
bnew = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
newgoals += goal_add (rddecrypt->next->message, smallrun, 1,
|
|
|
|
prioritylevel);
|
2006-02-26 20:01:22 +00:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("To this end, we added two new goals and one new send: ");
|
|
|
|
termPrint (rddecrypt->message);
|
|
|
|
eprintf (",");
|
|
|
|
termPrint (rddecrypt->next->message);
|
|
|
|
eprintf (",");
|
|
|
|
termPrint (rddecrypt->next->next->message);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
|
2006-02-26 17:18:59 +00:00
|
|
|
/*
|
2006-02-26 20:01:22 +00:00
|
|
|
* 3. Bind open goal to decryptor?
|
2006-02-26 17:18:59 +00:00
|
|
|
*/
|
2006-02-26 20:01:22 +00:00
|
|
|
if (goal_bind (bnew, r, e))
|
2006-02-26 17:18:59 +00:00
|
|
|
{
|
2006-02-26 20:01:22 +00:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Bound: trying new subterm_unfication_needs.\n");
|
|
|
|
}
|
|
|
|
subterm_unification_needs (TermOp (tbig), smallrun, 2);
|
|
|
|
goal_unbind (bnew);
|
2006-02-26 17:18:59 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* clean up
|
|
|
|
*/
|
|
|
|
termDelete (keyneeded);
|
|
|
|
goal_remove_last (newgoals);
|
|
|
|
semiRunDestroy ();
|
2006-02-26 20:01:22 +00:00
|
|
|
indentDepth--;
|
2006-02-26 17:18:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
old_length = sys->runs[run].height;
|
2006-02-26 20:01:22 +00:00
|
|
|
if (index >= old_length)
|
2006-02-26 17:18:59 +00:00
|
|
|
{
|
|
|
|
newgoals = add_read_goals (run, old_length, index + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newgoals = 0;
|
|
|
|
}
|
2006-02-26 20:01:22 +00:00
|
|
|
goalterm = roledef_shift (sys->runs[run].start, index)->message;
|
|
|
|
subterm_unification_needs (goalterm, run, index);
|
2006-02-26 17:18:59 +00:00
|
|
|
if (newgoals > 0)
|
|
|
|
{
|
|
|
|
goal_remove_last (newgoals);
|
|
|
|
}
|
|
|
|
sys->runs[run].height = old_length;
|
|
|
|
}
|
|
|
|
|
2004-08-16 10:50:37 +01:00
|
|
|
//! Try to bind a specific existing run to a goal.
|
2004-08-15 20:58:26 +01:00
|
|
|
/**
|
2004-08-16 10:50:37 +01:00
|
|
|
* The key goals are bound to the goal.
|
2005-05-17 19:45:01 +01:00
|
|
|
*
|
|
|
|
*@todo This is currently NOT correct. The point is that the key chain
|
|
|
|
* cannot uniquely define a path through a term in general, and
|
|
|
|
* a rewrite of termMguSubterm is needed. It should not yield the
|
|
|
|
* needed keys, but simply the path throught the term. This would enable
|
|
|
|
* reconstruction of the keys anyway. TODO
|
|
|
|
*
|
2006-01-02 21:06:08 +00:00
|
|
|
*@param b binding to fix (bind), destination filled in
|
|
|
|
*@param run run of binding start
|
|
|
|
*@param index index in run of binding start
|
2004-08-15 20:58:26 +01:00
|
|
|
*/
|
2004-08-11 15:09:12 +01:00
|
|
|
int
|
2006-02-26 17:18:59 +00:00
|
|
|
bind_existing_to_goal_old (const Binding b, const int run, const int index)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
|
|
|
Roledef rd;
|
|
|
|
int flag;
|
2004-08-16 14:18:04 +01:00
|
|
|
int old_length;
|
2004-08-18 10:57:01 +01:00
|
|
|
int newgoals;
|
2004-08-19 13:35:51 +01:00
|
|
|
int found;
|
2004-08-16 10:50:37 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
int subterm_iterate (Termlist substlist, Termlist cryptlist)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
|
|
|
int flag;
|
|
|
|
|
2004-08-19 13:35:51 +01:00
|
|
|
found++;
|
2004-08-16 10:50:37 +01:00
|
|
|
flag = 1;
|
2004-08-30 14:57:16 +01:00
|
|
|
/**
|
|
|
|
* Now create the new bindings
|
|
|
|
*/
|
2005-05-17 19:45:01 +01:00
|
|
|
int newgoals;
|
|
|
|
int newruns;
|
|
|
|
int stillvalid;
|
|
|
|
|
|
|
|
Binding smalltermbinding;
|
|
|
|
|
|
|
|
stillvalid = true; // New stuff is valid (no cycles)
|
|
|
|
newgoals = 0; // No new goals introduced (yet)
|
|
|
|
newruns = 0; // New runs introduced
|
|
|
|
smalltermbinding = b; // Start off with destination binding
|
|
|
|
|
2005-05-19 15:43:32 +01:00
|
|
|
indentDepth++;
|
2005-05-17 19:45:01 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (4))
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf ("Trying to bind the small term ");
|
2005-05-17 19:45:01 +01:00
|
|
|
termPrint (b->term);
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf (" as coming from the big send ");
|
2005-05-17 19:45:01 +01:00
|
|
|
termPrint (rd->message);
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf (" , binding ");
|
2005-05-17 19:45:01 +01:00
|
|
|
termPrint (b->term);
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf ("\nCrypted list needed: ");
|
2005-05-17 19:45:01 +01:00
|
|
|
termlistPrint (cryptlist);
|
2006-02-26 15:00:58 +00:00
|
|
|
eprintf ("\n");
|
2005-05-17 19:45:01 +01:00
|
|
|
}
|
|
|
|
#endif
|
2005-06-07 16:02:27 +01:00
|
|
|
if (cryptlist != NULL && switches.output == PROOF)
|
2005-05-17 19:45:01 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
2005-05-19 15:43:32 +01:00
|
|
|
("This introduces the obligation to decrypt the following encrypted subterms: ");
|
2005-05-17 19:45:01 +01:00
|
|
|
termlistPrint (cryptlist);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
2004-08-16 14:18:04 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
/* The order of the cryptlist is inner -> outer */
|
|
|
|
while (stillvalid && cryptlist != NULL && smalltermbinding != NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Invariants:
|
|
|
|
*
|
|
|
|
* smalltermbinding binding to be satisfied next (and for which a decryptor is needed)
|
|
|
|
*/
|
|
|
|
Term keyneeded;
|
|
|
|
int prioritylevel;
|
|
|
|
int smallrun;
|
|
|
|
int count;
|
|
|
|
Roledef rddecrypt;
|
|
|
|
Binding bnew;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 1. Add decryptor
|
|
|
|
*/
|
|
|
|
|
|
|
|
keyneeded =
|
|
|
|
inverseKey (sys->know->inverses, TermKey (cryptlist->term));
|
|
|
|
prioritylevel = getPriorityOfNeededKey (sys, keyneeded);
|
|
|
|
smallrun = create_decryptor (cryptlist->term, keyneeded);
|
|
|
|
rddecrypt = sys->runs[smallrun].start;
|
|
|
|
termDelete (keyneeded);
|
|
|
|
newruns++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 2. Add goal bindings
|
|
|
|
*/
|
|
|
|
|
|
|
|
count = goal_add (rddecrypt->message, smallrun, 0, 0);
|
|
|
|
newgoals = newgoals + count;
|
|
|
|
if (count >= 0)
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
if (count > 1)
|
|
|
|
{
|
|
|
|
error
|
|
|
|
("Added more than one goal for decryptor goal 1, weird.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This is the unique new goal then
|
|
|
|
bnew = (Binding) sys->bindings->data;
|
|
|
|
}
|
2004-08-18 15:06:14 +01:00
|
|
|
}
|
2005-05-17 19:45:01 +01:00
|
|
|
else
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
// No new binding? Weird, but fair enough
|
|
|
|
bnew = NULL;
|
|
|
|
}
|
|
|
|
newgoals =
|
|
|
|
newgoals + goal_add (rddecrypt->next->message, smallrun, 1,
|
|
|
|
prioritylevel);
|
2004-10-14 16:09:48 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
/*
|
|
|
|
* 3. Bind open goal to decryptor
|
|
|
|
*/
|
|
|
|
|
|
|
|
res = goal_bind (smalltermbinding, smallrun, 2); // returns 0 iff invalid
|
|
|
|
if (res != 0)
|
|
|
|
{
|
|
|
|
// Allright, good binding, proceed with next
|
|
|
|
smalltermbinding = bnew;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stillvalid = false;
|
2004-08-18 15:06:14 +01:00
|
|
|
}
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
/* progression */
|
|
|
|
cryptlist = cryptlist->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decryptors for any nested keys have been added. Now we can fill the
|
|
|
|
* final binding.
|
|
|
|
*/
|
2004-08-18 15:06:14 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
if (stillvalid)
|
|
|
|
{
|
|
|
|
if (goal_bind (smalltermbinding, run, index))
|
|
|
|
{
|
|
|
|
proof_suppose_binding (b);
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (4))
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Added %i new goals, iterating.\n", newgoals);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Iterate process */
|
|
|
|
indentDepth++;
|
|
|
|
flag = flag && iterate ();
|
|
|
|
indentDepth--;
|
2006-02-26 15:00:58 +00:00
|
|
|
|
|
|
|
goal_unbind (b);
|
2005-05-17 19:45:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
proof_cannot_bind (b, run, index);
|
|
|
|
}
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
2005-05-17 19:45:01 +01:00
|
|
|
|
|
|
|
goal_remove_last (newgoals);
|
|
|
|
while (newruns > 0)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
semiRunDestroy ();
|
|
|
|
newruns--;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
2005-05-19 15:43:32 +01:00
|
|
|
|
|
|
|
indentDepth--;
|
2004-08-16 10:50:37 +01:00
|
|
|
return flag;
|
|
|
|
}
|
|
|
|
|
2004-08-16 14:18:04 +01:00
|
|
|
//----------------------------
|
2004-08-16 10:50:37 +01:00
|
|
|
// Roledef entry
|
|
|
|
rd = roledef_shift (sys->runs[run].start, index);
|
|
|
|
|
2004-08-16 14:18:04 +01:00
|
|
|
// Fix length
|
2006-01-02 21:06:08 +00:00
|
|
|
old_length = sys->runs[run].height;
|
2004-08-16 14:18:04 +01:00
|
|
|
if ((index + 1) > old_length)
|
2004-08-18 15:06:14 +01:00
|
|
|
newgoals = add_read_goals (run, old_length, index + 1);
|
2004-08-18 10:57:01 +01:00
|
|
|
else
|
2004-08-18 15:06:14 +01:00
|
|
|
newgoals = 0;
|
2004-08-16 14:18:04 +01:00
|
|
|
|
2004-08-19 11:46:27 +01:00
|
|
|
// Bind to existing run
|
2004-08-19 13:35:51 +01:00
|
|
|
found = 0;
|
2004-08-18 15:06:14 +01:00
|
|
|
flag = termMguSubTerm (b->term, rd->message,
|
|
|
|
subterm_iterate, sys->know->inverses, NULL);
|
2004-08-19 13:35:51 +01:00
|
|
|
// Did it work?
|
2005-06-07 16:02:27 +01:00
|
|
|
if (found == 0 && switches.output == PROOF)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
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);
|
2004-08-19 13:35:51 +01:00
|
|
|
}
|
2004-08-16 14:18:04 +01:00
|
|
|
// Reset length
|
2004-10-18 14:04:34 +01:00
|
|
|
goal_remove_last (newgoals);
|
2006-01-02 21:06:08 +00:00
|
|
|
sys->runs[run].height = old_length;
|
2004-08-16 14:18:04 +01:00
|
|
|
return flag;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Bind a goal to an existing regular run, if possible
|
|
|
|
int
|
2004-08-18 10:57:01 +01:00
|
|
|
bind_existing_run (const Binding b, const Protocol p, const Role r,
|
2004-08-18 20:43:58 +01:00
|
|
|
const int index)
|
2004-08-11 15:09:12 +01:00
|
|
|
{
|
|
|
|
int run, flag;
|
2004-08-19 12:37:41 +01:00
|
|
|
int found;
|
2004-08-11 15:09:12 +01:00
|
|
|
|
|
|
|
flag = 1;
|
2004-08-19 12:37:41 +01:00
|
|
|
found = 0;
|
2004-08-11 15:09:12 +01:00
|
|
|
for (run = 0; run < sys->maxruns; run++)
|
|
|
|
{
|
2004-08-16 14:18:04 +01:00
|
|
|
if (sys->runs[run].protocol == p && sys->runs[run].role == r)
|
|
|
|
{
|
2004-08-19 12:37:41 +01:00
|
|
|
found++;
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 12:37:41 +01:00
|
|
|
{
|
|
|
|
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++;
|
2006-02-26 20:01:22 +00:00
|
|
|
bind_existing_to_goal (b, run, index);
|
2004-08-19 12:37:41 +01:00
|
|
|
indentDepth--;
|
2004-08-16 14:18:04 +01:00
|
|
|
}
|
2004-08-11 15:09:12 +01:00
|
|
|
}
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF && found == 0)
|
2004-08-19 12:37:41 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("There is no existing run for ");
|
|
|
|
termPrint (p->nameterm);
|
|
|
|
eprintf (", ");
|
|
|
|
termPrint (r->nameterm);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
2004-08-11 15:09:12 +01:00
|
|
|
return flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Bind a goal to a new run
|
|
|
|
int
|
2004-08-18 10:57:01 +01:00
|
|
|
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 15:09:12 +01:00
|
|
|
{
|
2004-08-11 16:05:13 +01:00
|
|
|
int run;
|
2004-08-18 10:57:01 +01:00
|
|
|
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);
|
2005-03-07 15:38:01 +00:00
|
|
|
{
|
|
|
|
newgoals = add_read_goals (run, 0, index + 1);
|
|
|
|
indentDepth++;
|
2006-02-26 20:01:22 +00:00
|
|
|
bind_existing_to_goal (b, run, index);
|
2005-03-07 15:38:01 +00:00
|
|
|
indentDepth--;
|
|
|
|
goal_remove_last (newgoals);
|
|
|
|
}
|
2004-08-19 13:47:53 +01:00
|
|
|
semiRunDestroy ();
|
2006-02-26 20:01:22 +00:00
|
|
|
return true;
|
2004-08-11 15:09:12 +01:00
|
|
|
}
|
|
|
|
|
2004-08-13 09:29:11 +01:00
|
|
|
//! Print the current semistate
|
|
|
|
void
|
|
|
|
printSemiState ()
|
|
|
|
{
|
|
|
|
int run;
|
2004-08-14 15:38:30 +01:00
|
|
|
int open;
|
2004-08-15 18:50:41 +01:00
|
|
|
List bl;
|
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
int binding_state_print (void *dt)
|
2004-08-15 20:58:26 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
binding_indent_print ((Binding) dt, 1);
|
2004-08-15 20:58:26 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2004-08-13 09:29:11 +01:00
|
|
|
|
2004-08-14 15:38:30 +01:00
|
|
|
indentPrint ();
|
|
|
|
eprintf ("!! --=[ Semistate ]=--\n");
|
2004-08-27 19:18:16 +01:00
|
|
|
indentPrint ();
|
|
|
|
eprintf ("!!\n");
|
|
|
|
indentPrint ();
|
2005-05-01 14:32:50 +01:00
|
|
|
eprintf ("!! Trace length: %i\n", get_semitrace_length ());
|
2004-08-14 15:38:30 +01:00
|
|
|
open = 0;
|
2004-08-13 09:29:11 +01:00
|
|
|
for (run = 0; run < sys->maxruns; run++)
|
|
|
|
{
|
|
|
|
int index;
|
2004-08-15 18:16:13 +01:00
|
|
|
Role r;
|
2004-08-13 09:29:11 +01:00
|
|
|
Roledef rd;
|
2004-08-15 18:16:13 +01:00
|
|
|
Term oldagent;
|
2004-08-13 09:29:11 +01:00
|
|
|
|
2004-08-15 18:16:13 +01:00
|
|
|
indentPrint ();
|
|
|
|
eprintf ("!!\n");
|
2004-08-13 09:29:11 +01:00
|
|
|
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);
|
|
|
|
}
|
2004-08-13 09:29:11 +01:00
|
|
|
eprintf (" ]\n");
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
rd = sys->runs[run].start;
|
2006-01-02 21:06:08 +00:00
|
|
|
while (index < sys->runs[run].height)
|
2004-08-13 09:29:11 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
2004-08-14 15:38:30 +01:00
|
|
|
eprintf ("!! %i ", index);
|
2004-08-13 09:29:11 +01:00
|
|
|
roledefPrint (rd);
|
|
|
|
eprintf ("\n");
|
2004-08-14 15:38:30 +01:00
|
|
|
if (isGoal (rd) && !isBound (rd))
|
2004-08-14 17:12:32 +01:00
|
|
|
open++;
|
2004-08-13 09:29:11 +01:00
|
|
|
index++;
|
|
|
|
rd = rd->next;
|
|
|
|
}
|
|
|
|
}
|
2004-08-15 18:50:41 +01:00
|
|
|
if (sys->bindings != NULL)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("!!\n");
|
2004-08-18 15:06:14 +01:00
|
|
|
list_iterate (sys->bindings, binding_state_print);
|
2004-08-15 18:50:41 +01:00
|
|
|
}
|
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);
|
2004-08-13 09:29:11 +01:00
|
|
|
}
|
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
//! Check if a binding duplicates an old one: if so, simply connect
|
|
|
|
int
|
|
|
|
bind_old_goal (const Binding b_new)
|
|
|
|
{
|
|
|
|
if (!b_new->done)
|
|
|
|
{
|
|
|
|
List bl;
|
|
|
|
|
|
|
|
bl = sys->bindings;
|
|
|
|
while (bl != NULL)
|
|
|
|
{
|
|
|
|
Binding b_old;
|
|
|
|
|
|
|
|
b_old = (Binding) bl->data;
|
|
|
|
if (b_old->done && isTermEqual (b_new->term, b_old->term))
|
|
|
|
{
|
|
|
|
// Old is done and has the same term!
|
2006-02-26 15:00:58 +00:00
|
|
|
// So we try to copy this binding, and fix it.
|
|
|
|
if (goal_bind (b_new, b_old->run_from, b_old->ev_from))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2005-03-08 13:02:16 +00:00
|
|
|
}
|
|
|
|
bl = bl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// No old binding to connect to
|
2006-02-26 15:00:58 +00:00
|
|
|
return false;
|
2005-03-08 13:02:16 +00:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2005-03-07 15:38:01 +00:00
|
|
|
Termlist m0tl, tl;
|
2004-08-18 19:22:59 +01:00
|
|
|
int flag;
|
2004-08-19 13:35:51 +01:00
|
|
|
int found;
|
2004-08-18 19:22:59 +01:00
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2004-08-18 19:22:59 +01:00
|
|
|
flag = 1;
|
2004-08-19 13:35:51 +01:00
|
|
|
found = 0;
|
2004-08-18 19:22:59 +01:00
|
|
|
m0tl = knowledgeSet (sys->know);
|
2004-12-08 16:25:27 +00:00
|
|
|
tl = m0tl;
|
|
|
|
while (flag && tl != NULL)
|
2004-08-18 19:22:59 +01:00
|
|
|
{
|
|
|
|
Term m0t;
|
|
|
|
Termlist subst;
|
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
m0t = tl->term;
|
2004-08-18 19:22:59 +01:00
|
|
|
subst = termMguTerm (b->term, m0t);
|
|
|
|
if (subst != MGUFAIL)
|
|
|
|
{
|
|
|
|
int run;
|
|
|
|
|
2004-12-08 19:30:26 +00:00
|
|
|
I_M->roledef->message = m0t;
|
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);
|
2006-01-02 21:06:08 +00:00
|
|
|
sys->runs[run].height = 1;
|
2005-03-07 15:38:01 +00:00
|
|
|
{
|
|
|
|
indentDepth++;
|
|
|
|
if (goal_bind (b, run, 0))
|
|
|
|
{
|
|
|
|
found++;
|
|
|
|
proof_suppose_binding (b);
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2005-03-07 15:38:01 +00:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("* I.e. retrieving ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf (" from the initial knowledge.\n");
|
|
|
|
}
|
|
|
|
flag = flag && iterate ();
|
2006-02-26 15:00:58 +00:00
|
|
|
goal_unbind (b);
|
2005-03-07 15:38:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
proof_cannot_bind (b, run, 0);
|
|
|
|
}
|
|
|
|
indentDepth--;
|
|
|
|
}
|
2004-08-19 13:47:53 +01:00
|
|
|
semiRunDestroy ();
|
2004-08-19 15:49:03 +01:00
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2004-08-18 19:22:59 +01:00
|
|
|
termlistSubstReset (subst);
|
|
|
|
termlistDelete (subst);
|
|
|
|
}
|
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
tl = tl->next;
|
2004-08-18 19:22:59 +01:00
|
|
|
}
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (found == 0 && switches.output == PROOF)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
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);
|
2005-03-07 15:38:01 +00:00
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2004-08-18 19:22:59 +01:00
|
|
|
return flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Bind an intruder goal by intruder composition construction
|
2004-08-13 21:56:51 +01:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
{
|
2004-08-13 21:09:12 +01:00
|
|
|
Term term;
|
2004-08-16 15:49:41 +01:00
|
|
|
int flag;
|
2004-08-19 15:49:03 +01:00
|
|
|
int can_be_encrypted;
|
2004-08-13 21:09:12 +01:00
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2004-08-16 15:49:41 +01:00
|
|
|
flag = 1;
|
2004-08-19 15:55:21 +01:00
|
|
|
term = deVar (b->term);
|
2004-08-19 15:49:03 +01:00
|
|
|
can_be_encrypted = 0;
|
2004-08-18 19:22:59 +01:00
|
|
|
|
2004-08-13 21:09:12 +01:00
|
|
|
if (!realTermLeaf (term))
|
|
|
|
{
|
2004-08-18 16:46:33 +01:00
|
|
|
int run;
|
|
|
|
int index;
|
|
|
|
int newgoals;
|
|
|
|
Roledef rd;
|
2004-08-13 21:09:12 +01:00
|
|
|
Term t1, t2;
|
|
|
|
|
2004-08-19 15:49:03 +01:00
|
|
|
if (!realTermEncrypt (term))
|
2004-08-13 21:09:12 +01:00
|
|
|
{
|
|
|
|
// tuple construction
|
2004-08-18 16:46:33 +01:00
|
|
|
error ("Goal that is a tuple should not occur!");
|
2004-08-13 21:09:12 +01:00
|
|
|
}
|
|
|
|
|
2004-08-18 16:46:33 +01:00
|
|
|
// must be encryption
|
2004-11-16 12:07:55 +00:00
|
|
|
t1 = TermOp (term);
|
|
|
|
t2 = TermKey (term);
|
2004-08-18 16:46:33 +01:00
|
|
|
|
2004-08-19 15:49:03 +01:00
|
|
|
if (t2 != TERM_Hidden)
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
2004-08-19 15:49:03 +01:00
|
|
|
can_be_encrypted = 1;
|
|
|
|
run = semiRunCreate (INTRUDER, I_RRS);
|
|
|
|
rd = sys->runs[run].start;
|
2004-08-19 15:52:17 +01:00
|
|
|
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);
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 15:49:03 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("* Encrypting ");
|
|
|
|
termPrint (term);
|
|
|
|
eprintf (" using term ");
|
|
|
|
termPrint (t1);
|
|
|
|
eprintf (" and key ");
|
|
|
|
termPrint (t2);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
2004-12-09 13:34:36 +00:00
|
|
|
newgoals = add_read_goals (run, 0, index + 1);
|
2004-08-19 15:55:21 +01:00
|
|
|
|
2004-12-09 13:34:36 +00:00
|
|
|
indentDepth++;
|
|
|
|
if (goal_bind (b, run, index))
|
|
|
|
{
|
|
|
|
proof_suppose_binding (b);
|
|
|
|
flag = flag && iterate ();
|
2006-02-26 15:00:58 +00:00
|
|
|
goal_unbind (b);
|
2004-08-19 15:49:03 +01:00
|
|
|
}
|
2004-12-09 13:34:36 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
proof_cannot_bind (b, run, index);
|
|
|
|
}
|
|
|
|
indentDepth--;
|
|
|
|
goal_remove_last (newgoals);
|
2004-08-19 15:49:03 +01:00
|
|
|
semiRunDestroy ();
|
2004-08-19 12:37:41 +01:00
|
|
|
}
|
2004-08-13 21:09:12 +01:00
|
|
|
}
|
2004-08-19 15:49:03 +01:00
|
|
|
|
|
|
|
if (!can_be_encrypted)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Term ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf (" cannot be constructed by encryption.\n");
|
|
|
|
}
|
|
|
|
}
|
2004-12-08 16:25:27 +00:00
|
|
|
|
|
|
|
|
2004-08-16 15:49:41 +01:00
|
|
|
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
|
|
|
|
/**
|
2005-03-08 13:02:16 +00:00
|
|
|
* Handles the case where the intruder constructs a composed term himself, or retrieves it from m0.
|
|
|
|
* However, it must not already have been created in an intruder run; then it gets bound to that.
|
2004-08-18 19:22:59 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
bind_goal_new_intruder_run (const Binding b)
|
|
|
|
{
|
2004-08-19 13:35:51 +01:00
|
|
|
int flag;
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
//! Bind a regular goal
|
2004-08-30 23:08:44 +01:00
|
|
|
/**
|
|
|
|
* Problem child. Valgrind does not like it.
|
|
|
|
*/
|
2004-08-11 13:08:10 +01:00
|
|
|
int
|
2004-08-18 16:46:33 +01:00
|
|
|
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
|
|
|
|
2004-08-30 22:49:51 +01:00
|
|
|
int test_sub_unification (Termlist substlist, Termlist keylist)
|
|
|
|
{
|
|
|
|
// A unification exists; return the signal
|
|
|
|
return 0;
|
|
|
|
}
|
2004-08-18 15:06:14 +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)
|
|
|
|
{
|
2004-08-18 16:46:33 +01:00
|
|
|
if (p == INTRUDER)
|
|
|
|
{
|
|
|
|
// No intruder roles here
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
// 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
|
2004-11-16 12:07:55 +00:00
|
|
|
(b->term, rd->message, test_sub_unification, sys->know->inverses,
|
|
|
|
NULL))
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
2004-08-30 23:08:44 +01:00
|
|
|
int sflag;
|
2004-08-18 15:06:14 +01:00
|
|
|
|
|
|
|
// A good candidate
|
2004-08-19 12:37:41 +01:00
|
|
|
found++;
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF && found == 1)
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
2004-08-19 13:35:51 +01:00
|
|
|
eprintf ("The term ", found);
|
2004-08-18 15:06:14 +01:00
|
|
|
termPrint (b->term);
|
2004-08-19 14:09:35 +01:00
|
|
|
eprintf
|
|
|
|
(" matches patterns from the role definitions. Investigate.\n");
|
2004-08-19 13:35:51 +01:00
|
|
|
}
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
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 (", ");
|
2004-08-18 15:06:14 +01:00
|
|
|
termPrint (r->nameterm);
|
2004-08-19 12:37:41 +01:00
|
|
|
eprintf (", at %i\n", index);
|
2004-08-18 15:06:14 +01:00
|
|
|
}
|
2004-08-19 13:35:51 +01:00
|
|
|
indentDepth++;
|
2005-05-19 15:43:32 +01:00
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
// Bind to existing run
|
2006-02-26 17:18:59 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
debug (5, "Trying to bind to existing run.");
|
|
|
|
#endif
|
2004-08-30 23:08:44 +01:00
|
|
|
sflag = bind_existing_run (b, p, r, index);
|
2004-08-18 16:46:33 +01:00
|
|
|
// bind to new run
|
2006-02-26 17:18:59 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
debug (5, "Trying to bind to new run.");
|
|
|
|
#endif
|
2005-05-19 15:43:32 +01:00
|
|
|
sflag = sflag && bind_new_run (b, p, r, index);
|
|
|
|
|
2004-08-19 13:35:51 +01:00
|
|
|
indentDepth--;
|
2004-08-30 23:08:44 +01:00
|
|
|
return sflag;
|
2004-08-18 15:06:14 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-27 18:35:23 +01:00
|
|
|
|
2004-08-18 16:46:33 +01:00
|
|
|
// 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);
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF && found == 0)
|
2004-08-19 12:37:41 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("The term ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf (" does not match any pattern from the role definitions.\n");
|
|
|
|
}
|
|
|
|
return flag;
|
2004-08-18 16:46:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
//! Bind to all possible sends of intruder runs
|
2004-08-18 20:43:58 +01:00
|
|
|
int
|
|
|
|
bind_goal_old_intruder_run (Binding b)
|
2004-08-18 16:46:33 +01:00
|
|
|
{
|
|
|
|
int run;
|
|
|
|
int flag;
|
2004-08-19 13:35:51 +01:00
|
|
|
int found;
|
2004-08-18 16:46:33 +01:00
|
|
|
|
2004-08-19 13:35:51 +01:00
|
|
|
found = 0;
|
2004-08-18 16:46:33 +01:00
|
|
|
flag = 1;
|
|
|
|
for (run = 0; run < sys->maxruns; run++)
|
|
|
|
{
|
|
|
|
if (sys->runs[run].protocol == INTRUDER)
|
|
|
|
{
|
|
|
|
int ev;
|
|
|
|
Roledef rd;
|
2004-08-18 15:06:14 +01:00
|
|
|
|
2004-08-18 20:43:58 +01:00
|
|
|
rd = sys->runs[run].start;
|
2004-08-18 16:46:33 +01:00
|
|
|
ev = 0;
|
2006-01-02 21:06:08 +00:00
|
|
|
while (ev < sys->runs[run].height)
|
2004-08-18 16:46:33 +01:00
|
|
|
{
|
|
|
|
if (rd->type == SEND)
|
|
|
|
{
|
2004-08-19 13:35:51 +01:00
|
|
|
found++;
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF && found == 1)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
2004-08-19 14:09:35 +01:00
|
|
|
eprintf
|
|
|
|
("Suppose it is from an existing intruder run.\n");
|
2004-08-19 13:35:51 +01:00
|
|
|
}
|
2004-08-19 14:09:35 +01:00
|
|
|
indentDepth++;
|
2006-02-26 20:01:22 +00:00
|
|
|
bind_existing_to_goal (b, run, ev);
|
2004-08-19 14:09:35 +01:00
|
|
|
indentDepth--;
|
2004-08-18 16:46:33 +01:00
|
|
|
}
|
|
|
|
rd = rd->next;
|
|
|
|
ev++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF && found == 0)
|
2004-08-19 13:35:51 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("No existing intruder runs to match to.\n");
|
|
|
|
}
|
2004-08-18 15:06:14 +01:00
|
|
|
return flag;
|
2004-08-11 13:08:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Bind a goal in all possible ways
|
|
|
|
int
|
2004-08-18 10:57:01 +01:00
|
|
|
bind_goal (const Binding b)
|
2004-08-11 13:08:10 +01:00
|
|
|
{
|
2005-01-14 18:18:40 +00:00
|
|
|
if (b->blocked)
|
|
|
|
{
|
|
|
|
error ("Trying to bind a blocked goal!");
|
|
|
|
}
|
2004-08-18 10:57:01 +01:00
|
|
|
if (!b->done)
|
2004-08-11 13:08:10 +01:00
|
|
|
{
|
2004-08-18 16:46:33 +01:00
|
|
|
int flag;
|
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
flag = 1;
|
2004-08-19 11:46:27 +01:00
|
|
|
proof_select_goal (b);
|
|
|
|
indentDepth++;
|
2004-08-20 12:47:00 +01:00
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
// Consider a duplicate goal that we already bound before (C-minimality)
|
|
|
|
// if (1 == 0)
|
|
|
|
if (bind_old_goal (b))
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2005-03-08 13:02:16 +00:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Goal for term ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf (" was bound once before, linking up to #%i, %i.\n",
|
|
|
|
b->run_from, b->ev_from);
|
|
|
|
}
|
2004-08-27 18:35:23 +01:00
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
flag = flag && iterate ();
|
|
|
|
|
|
|
|
// Unbind again
|
2006-02-26 15:00:58 +00:00
|
|
|
goal_unbind (b);
|
2005-03-08 13:02:16 +00:00
|
|
|
indentDepth--;
|
|
|
|
return flag;
|
|
|
|
}
|
|
|
|
else
|
2004-08-20 12:47:00 +01:00
|
|
|
{
|
2006-01-17 16:18:26 +00:00
|
|
|
int know_only;
|
2005-03-08 13:02:16 +00:00
|
|
|
|
|
|
|
know_only = 0;
|
2006-01-17 16:18:26 +00:00
|
|
|
|
|
|
|
if (1 == 0) // blocked for now
|
2005-03-08 13:02:16 +00:00
|
|
|
{
|
2006-01-17 16:18:26 +00:00
|
|
|
// Prune: if it is an SK type construct, ready
|
|
|
|
// No regular run will apply SK for you.
|
|
|
|
//!@todo This still needs a lemma, and a more generic (correct) algorithm!! It is currently
|
|
|
|
// actually false, e.g. for signing protocols, and password-like functions.
|
|
|
|
//
|
|
|
|
Term function;
|
|
|
|
|
|
|
|
function = getTermFunction (b->term);
|
|
|
|
if (function != NULL)
|
2005-03-08 13:02:16 +00:00
|
|
|
{
|
2006-01-17 16:18:26 +00:00
|
|
|
if (!inKnowledge (sys->know, function))
|
2005-03-08 13:02:16 +00:00
|
|
|
{
|
2006-01-17 16:18:26 +00:00
|
|
|
// Prune because we didn't know it before, and it is never subterm-sent
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("* Because ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf
|
|
|
|
(" is never sent from a regular run, so we only intruder construct it.\n");
|
|
|
|
}
|
|
|
|
know_only = 1;
|
2005-03-08 13:02:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-22 09:53:50 +00:00
|
|
|
if (switches.experimental & 4 == 0)
|
2004-08-20 12:47:00 +01:00
|
|
|
{
|
2006-02-22 09:53:50 +00:00
|
|
|
// Keylevel lemmas: improves on the previous one
|
|
|
|
if (!isPossiblySent (b->term))
|
2004-08-20 12:47:00 +01:00
|
|
|
{
|
2006-02-22 09:53:50 +00:00
|
|
|
if (switches.output == PROOF)
|
2005-03-08 13:02:16 +00:00
|
|
|
{
|
2006-02-22 09:53:50 +00:00
|
|
|
eprintf
|
|
|
|
("Rejecting a term as a regular bind because key levels are off: ");
|
|
|
|
termPrint (b->term);
|
|
|
|
if (know_only)
|
|
|
|
{
|
|
|
|
eprintf (" [in accordance with function lemma]");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eprintf (" [stronger than function lemma]");
|
|
|
|
}
|
|
|
|
eprintf ("\n");
|
2005-03-08 13:02:16 +00:00
|
|
|
}
|
2006-02-22 09:53:50 +00:00
|
|
|
know_only = 1;
|
2004-08-20 12:47:00 +01:00
|
|
|
}
|
|
|
|
}
|
2005-03-08 13:02:16 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (DEBUGL (5) && know_only == 1)
|
|
|
|
{
|
|
|
|
eprintf
|
|
|
|
("Keylevel lemma is weaker than function lemma for term ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2004-08-27 18:35:23 +01:00
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
proofDepth++;
|
|
|
|
if (know_only)
|
|
|
|
{
|
|
|
|
// Special case: only from intruder
|
|
|
|
flag = flag && bind_goal_old_intruder_run (b);
|
|
|
|
flag = flag && bind_goal_new_intruder_run (b);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Normal case
|
|
|
|
{
|
|
|
|
flag = bind_goal_regular_run (b);
|
|
|
|
}
|
|
|
|
flag = flag && bind_goal_old_intruder_run (b);
|
|
|
|
flag = flag && bind_goal_new_intruder_run (b);
|
|
|
|
}
|
|
|
|
proofDepth--;
|
2004-08-20 12:47:00 +01:00
|
|
|
|
2005-03-08 13:02:16 +00:00
|
|
|
indentDepth--;
|
|
|
|
return flag;
|
|
|
|
}
|
2004-08-11 13:08:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-15 13:24:27 +01:00
|
|
|
return 1;
|
2004-08-11 13:08:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-12 21:13:00 +00:00
|
|
|
//! Create a generic new term of the same type, with a new run identifier.
|
|
|
|
/**
|
|
|
|
* Output: the first element of the returned list.
|
|
|
|
*/
|
|
|
|
Termlist
|
|
|
|
createNewTermGeneric (Termlist tl, Term t)
|
|
|
|
{
|
|
|
|
int freenumber;
|
|
|
|
Termlist tlscan;
|
|
|
|
Term newterm;
|
|
|
|
|
|
|
|
/* Determine first free number */
|
|
|
|
freenumber = 0;
|
|
|
|
tlscan = tl;
|
|
|
|
while (tlscan != NULL)
|
|
|
|
{
|
|
|
|
Term ts;
|
|
|
|
|
|
|
|
ts = tlscan->term;
|
|
|
|
if (isLeafNameEqual (t, ts))
|
|
|
|
{
|
|
|
|
if (TermRunid (ts) >= freenumber)
|
|
|
|
{
|
|
|
|
freenumber = TermRunid (ts) + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tlscan = tlscan->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make a new term with the free number */
|
|
|
|
newterm = (Term) memAlloc (sizeof (struct term));
|
|
|
|
memcpy (newterm, t, sizeof (struct term));
|
|
|
|
TermRunid (newterm) = freenumber;
|
|
|
|
|
|
|
|
/* return */
|
|
|
|
return termlistPrepend (tl, newterm);
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Create a new term with incremented run rumber, starting at sys->maxruns.
|
|
|
|
/**
|
2006-01-02 20:18:47 +00:00
|
|
|
* This is a rather intricate function that tries to generate new terms of a
|
|
|
|
* certain type. It first looks up things in the initial knowledge, checking
|
|
|
|
* whether they are used already. After that, new ones are generated.
|
|
|
|
*
|
2005-11-12 21:13:00 +00:00
|
|
|
* Output: the first element of the returned list.
|
|
|
|
*/
|
|
|
|
Termlist
|
|
|
|
createNewTerm (Termlist tl, Term t, int isagent)
|
|
|
|
{
|
|
|
|
/* Does if have an explicit type?
|
|
|
|
* If so, we try to find a fresh name from the intruder knowledge first.
|
|
|
|
*/
|
|
|
|
if (isagent)
|
|
|
|
{
|
|
|
|
Termlist knowlist;
|
|
|
|
Termlist kl;
|
|
|
|
|
|
|
|
knowlist = knowledgeSet (sys->know);
|
|
|
|
kl = knowlist;
|
|
|
|
while (kl != NULL)
|
|
|
|
{
|
|
|
|
Term k;
|
|
|
|
|
|
|
|
k = kl->term;
|
|
|
|
if (isAgentType (k->stype))
|
|
|
|
{
|
|
|
|
/* agent */
|
|
|
|
/* We don't want to instantiate untrusted agents. */
|
|
|
|
if (!inTermlist (sys->untrusted, k))
|
|
|
|
{
|
|
|
|
/* trusted agent */
|
|
|
|
if (!inTermlist (tl, k))
|
|
|
|
{
|
|
|
|
/* This agent name is not in the list yet. */
|
|
|
|
return termlistPrepend (tl, k);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kl = kl->next;
|
|
|
|
}
|
|
|
|
termlistDelete (knowlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not an agent or no free one found */
|
|
|
|
return createNewTermGeneric (tl, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Delete a term made in the previous constructions
|
2006-01-02 20:18:47 +00:00
|
|
|
/**
|
|
|
|
* \sa createNewTerm
|
|
|
|
*/
|
2005-11-12 21:13:00 +00:00
|
|
|
void
|
|
|
|
deleteNewTerm (Term t)
|
|
|
|
{
|
|
|
|
if (TermRunid (t) >= 0)
|
|
|
|
{
|
|
|
|
/* if it has a positive runid, it did not come from the intruder
|
|
|
|
* knowledge, so it must have been constructed.
|
|
|
|
*/
|
|
|
|
memFree (t, sizeof (struct term));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Make a trace concrete
|
2006-01-02 20:18:47 +00:00
|
|
|
/**
|
|
|
|
* People find reading variables in attack outputs difficult.
|
|
|
|
* Thus, we instantiate them in a sensible way to make things more readable.
|
|
|
|
*
|
|
|
|
* \sa makeTraceClass
|
|
|
|
*/
|
2005-11-12 21:13:00 +00:00
|
|
|
Termlist
|
|
|
|
makeTraceConcrete (const System sys)
|
|
|
|
{
|
|
|
|
Termlist changedvars;
|
|
|
|
Termlist tlnew;
|
|
|
|
int run;
|
|
|
|
|
|
|
|
changedvars = NULL;
|
|
|
|
tlnew = NULL;
|
|
|
|
run = 0;
|
|
|
|
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
Termlist tl;
|
|
|
|
|
|
|
|
tl = sys->runs[run].locals;
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
/* variable, and of some run? */
|
|
|
|
if (isTermVariable (tl->term) && TermRunid (tl->term) >= 0)
|
|
|
|
{
|
|
|
|
Term var;
|
|
|
|
Term name;
|
|
|
|
Termlist vartype;
|
|
|
|
|
|
|
|
var = deVar (tl->term);
|
|
|
|
vartype = var->stype;
|
|
|
|
// Determine class name
|
|
|
|
if (vartype != NULL)
|
|
|
|
{
|
|
|
|
// Take first type name
|
|
|
|
name = vartype->term;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Just a generic name
|
|
|
|
name = TERM_Data;
|
|
|
|
}
|
|
|
|
// We should turn this into an actual term
|
|
|
|
tlnew = createNewTerm (tlnew, name, isAgentType (var->stype));
|
|
|
|
var->subst = tlnew->term;
|
|
|
|
|
|
|
|
// Store for undo later
|
|
|
|
changedvars = termlistAdd (changedvars, var);
|
|
|
|
}
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
termlistDelete (tlnew);
|
|
|
|
return changedvars;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Make a trace a class again
|
2006-01-02 20:18:47 +00:00
|
|
|
/**
|
|
|
|
* \sa makeTraceConcrete
|
|
|
|
*/
|
2005-11-12 21:13:00 +00:00
|
|
|
void
|
|
|
|
makeTraceClass (const System sys, Termlist varlist)
|
|
|
|
{
|
|
|
|
Termlist tl;
|
|
|
|
|
|
|
|
tl = varlist;
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
Term var;
|
|
|
|
|
|
|
|
var = tl->term;
|
|
|
|
deleteNewTerm (var->subst);
|
|
|
|
var->subst = NULL;
|
|
|
|
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
termlistDelete (varlist);
|
|
|
|
}
|
|
|
|
|
2005-12-27 10:49:22 +00:00
|
|
|
//! Start attack output
|
|
|
|
void
|
|
|
|
attackOutputStart (void)
|
|
|
|
{
|
|
|
|
if (switches.prune == 2)
|
|
|
|
{
|
|
|
|
FILE *fd;
|
|
|
|
|
|
|
|
// Close old file (if any)
|
|
|
|
if (attack_stream != NULL)
|
|
|
|
{
|
|
|
|
fclose (attack_stream); // this automatically discards the old temporary file
|
|
|
|
}
|
|
|
|
// Create new file
|
|
|
|
fd = scyther_tempfile ();
|
|
|
|
attack_stream = fd;
|
|
|
|
globalStream = (char *) attack_stream;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Stop attack output
|
|
|
|
void
|
|
|
|
attackOutputStop (void)
|
|
|
|
{
|
|
|
|
// Nothing to do, just leave the opened tmpfile
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Copy one (finite) stream from beginning to end to another
|
|
|
|
/**
|
|
|
|
* Ugly first implementation, something to improve later (although it is not
|
|
|
|
* crucial code in any way)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fcopy (FILE * fromstream, FILE * tostream)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
// 'Just to be sure'
|
|
|
|
fflush (fromstream);
|
|
|
|
fseek (fromstream, 0, SEEK_SET);
|
|
|
|
|
|
|
|
// Urgh, using the assignment in the loop condition, brrr. Fugly.
|
|
|
|
// Discourage.
|
|
|
|
while ((c = fgetc (fromstream)) != EOF)
|
|
|
|
{
|
|
|
|
fputc (c, tostream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-12 21:13:00 +00:00
|
|
|
//! Output an attack in the desired way
|
|
|
|
void
|
|
|
|
arachneOutputAttack ()
|
|
|
|
{
|
|
|
|
Termlist varlist;
|
|
|
|
|
2005-12-27 10:49:22 +00:00
|
|
|
// Make concrete
|
2005-11-12 21:13:00 +00:00
|
|
|
if (switches.concrete)
|
|
|
|
{
|
|
|
|
varlist = makeTraceConcrete (sys);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
varlist = NULL;
|
|
|
|
}
|
|
|
|
|
2005-12-27 10:49:22 +00:00
|
|
|
// Wrapper for the real output
|
|
|
|
attackOutputStart ();
|
|
|
|
|
|
|
|
// Generate the output, already!
|
2005-11-12 21:13:00 +00:00
|
|
|
if (switches.xml)
|
|
|
|
{
|
|
|
|
xmlOutSemitrace (sys);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-01-02 19:19:23 +00:00
|
|
|
dotSemiState (sys);
|
2005-11-12 21:13:00 +00:00
|
|
|
}
|
|
|
|
|
2005-12-27 10:49:22 +00:00
|
|
|
// End wrapper
|
|
|
|
attackOutputStop ();
|
|
|
|
|
|
|
|
// Undo concretization
|
2005-11-12 21:13:00 +00:00
|
|
|
makeTraceClass (sys, varlist);
|
|
|
|
}
|
|
|
|
|
2004-08-11 13:08:10 +01:00
|
|
|
//------------------------------------------------------------------------
|
|
|
|
// Main logic core
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
2006-01-02 19:19:23 +00:00
|
|
|
|
|
|
|
//! Selector to select the first tuple goal.
|
|
|
|
/**
|
|
|
|
* Basically to get rid of -m2 tuple goals.
|
|
|
|
* Nice iteration, I'd suppose
|
|
|
|
*/
|
|
|
|
Binding
|
|
|
|
select_tuple_goal ()
|
|
|
|
{
|
|
|
|
List bl;
|
|
|
|
Binding tuplegoal;
|
|
|
|
|
|
|
|
bl = sys->bindings;
|
|
|
|
tuplegoal = NULL;
|
|
|
|
while (bl != NULL && tuplegoal == NULL)
|
|
|
|
{
|
|
|
|
Binding b;
|
|
|
|
|
|
|
|
b = (Binding) bl->data;
|
|
|
|
// Ignore done stuff
|
|
|
|
if (!b->blocked && !b->done)
|
|
|
|
{
|
|
|
|
if (isTermTuple (b->term))
|
|
|
|
{
|
|
|
|
tuplegoal = b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bl = bl->next;
|
|
|
|
}
|
|
|
|
return tuplegoal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-11 10:51:17 +01:00
|
|
|
//! Main recursive procedure for Arachne
|
|
|
|
int
|
2004-08-11 15:09:12 +01:00
|
|
|
iterate ()
|
2004-08-11 12:22:20 +01:00
|
|
|
{
|
2004-08-11 22:04:52 +01:00
|
|
|
int flag;
|
2004-08-11 13:08:10 +01:00
|
|
|
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2004-08-11 22:04:52 +01:00
|
|
|
flag = 1;
|
2006-01-02 18:43:25 +00:00
|
|
|
if (!prune_theorems (sys))
|
2004-08-11 22:04:52 +01:00
|
|
|
{
|
2006-01-02 19:55:34 +00:00
|
|
|
if (!prune_claim_specifics (sys))
|
2004-08-19 14:09:35 +01:00
|
|
|
{
|
2006-01-02 18:43:25 +00:00
|
|
|
if (!prune_bounds (sys))
|
2004-08-27 16:02:33 +01:00
|
|
|
{
|
|
|
|
Binding b;
|
2004-08-11 13:08:10 +01:00
|
|
|
|
2005-01-14 14:08:01 +00:00
|
|
|
// Are there any tuple goals?
|
2005-03-07 15:38:01 +00:00
|
|
|
b = select_tuple_goal ();
|
2005-01-14 14:08:01 +00:00
|
|
|
if (b != NULL)
|
2004-08-19 14:09:35 +01:00
|
|
|
{
|
2005-01-14 14:08:01 +00:00
|
|
|
// Expand tuple goal
|
|
|
|
int count;
|
2005-03-07 15:38:01 +00:00
|
|
|
|
2005-01-14 18:18:40 +00:00
|
|
|
// mark as blocked for iteration
|
|
|
|
binding_block (b);
|
|
|
|
// simply adding will detect the tuple and add the new subgoals
|
|
|
|
count = goal_add (b->term, b->run_to, b->ev_to, b->level);
|
|
|
|
|
2005-01-14 14:08:01 +00:00
|
|
|
// Show this in output
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2004-08-27 16:02:33 +01:00
|
|
|
{
|
|
|
|
indentPrint ();
|
2005-01-14 14:08:01 +00:00
|
|
|
eprintf ("Expanding tuple goal ");
|
|
|
|
termPrint (b->term);
|
2005-01-14 18:18:40 +00:00
|
|
|
eprintf (" into %i subgoals.\n", count);
|
2004-08-27 16:02:33 +01:00
|
|
|
}
|
2005-01-14 14:08:01 +00:00
|
|
|
|
|
|
|
// iterate
|
|
|
|
flag = iterate ();
|
|
|
|
|
|
|
|
// undo
|
2005-03-07 15:38:01 +00:00
|
|
|
goal_remove_last (count);
|
2005-01-14 18:18:40 +00:00
|
|
|
binding_unblock (b);
|
2004-08-27 16:02:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-14 14:08:01 +00:00
|
|
|
// No tuple goals; good
|
|
|
|
Binding b;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Not pruned: count
|
|
|
|
*/
|
|
|
|
|
|
|
|
sys->states = statesIncrease (sys->states);
|
2006-02-22 08:24:29 +00:00
|
|
|
sys->current_claim->states =
|
|
|
|
statesIncrease (sys->current_claim->states);
|
2005-01-14 14:08:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check whether its a final state (i.e. all goals bound)
|
2004-08-27 16:02:33 +01:00
|
|
|
*/
|
2005-01-14 14:08:01 +00:00
|
|
|
|
2006-02-23 15:03:43 +00:00
|
|
|
b = (Binding) select_goal (sys);
|
2005-01-14 14:08:01 +00:00
|
|
|
if (b == NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* all goals bound, check for property
|
|
|
|
*/
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == PROOF)
|
2005-01-14 14:08:01 +00:00
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("All goals are now bound.\n");
|
|
|
|
}
|
|
|
|
sys->claims = statesIncrease (sys->claims);
|
2005-05-02 14:38:45 +01:00
|
|
|
sys->current_claim->count =
|
|
|
|
statesIncrease (sys->current_claim->count);
|
2006-01-02 20:18:47 +00:00
|
|
|
flag = property_check (sys);
|
2005-01-14 14:08:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* bind this goal in all possible ways and iterate
|
|
|
|
*/
|
|
|
|
flag = bind_goal (b);
|
|
|
|
}
|
2004-08-19 14:09:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-27 16:02:33 +01:00
|
|
|
// Pruned because of bound!
|
2005-05-02 14:38:45 +01:00
|
|
|
sys->current_claim->complete = 0;
|
2004-08-19 11:46:27 +01:00
|
|
|
}
|
2004-08-11 22:04:52 +01:00
|
|
|
}
|
2004-08-11 13:08:10 +01:00
|
|
|
}
|
2004-08-18 19:22:59 +01:00
|
|
|
|
2004-08-18 19:41:49 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (5) && !flag)
|
2004-08-18 19:22:59 +01:00
|
|
|
{
|
|
|
|
warning ("Flag has turned 0!");
|
|
|
|
}
|
2004-08-18 19:41:49 +01:00
|
|
|
#endif
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2004-08-11 22:04:52 +01:00
|
|
|
return flag;
|
2004-08-11 12:22:20 +01:00
|
|
|
}
|
|
|
|
|
2005-12-27 10:49:22 +00:00
|
|
|
//! Just before starting output of an attack.
|
|
|
|
//
|
|
|
|
//! A wrapper for the case in which we need to buffer attacks.
|
|
|
|
int
|
|
|
|
iterate_buffer_attacks (void)
|
|
|
|
{
|
|
|
|
if (switches.prune != 2)
|
|
|
|
{
|
|
|
|
return iterate ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We are pruning attacks, so they should go into a temporary file.
|
|
|
|
/*
|
|
|
|
* Set up the temporary file pointer
|
|
|
|
*/
|
|
|
|
char *buffer;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
// Push the old situation onto the stack
|
|
|
|
buffer = globalStream;
|
|
|
|
|
|
|
|
// Start stuff
|
|
|
|
attack_stream = NULL;
|
|
|
|
attackOutputStart ();
|
|
|
|
|
|
|
|
// Finally, proceed with iteration procedure
|
|
|
|
result = iterate ();
|
|
|
|
|
|
|
|
/* Now, if it has been set, we need to copy the output to the normal streams.
|
|
|
|
*/
|
|
|
|
fcopy (attack_stream, (FILE *) buffer);
|
|
|
|
|
|
|
|
// Close
|
|
|
|
fclose (attack_stream);
|
|
|
|
attack_stream = NULL;
|
|
|
|
|
|
|
|
// Restore
|
|
|
|
globalStream = buffer;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-11 12:22:20 +01:00
|
|
|
//! Main code for Arachne
|
|
|
|
/**
|
|
|
|
* For this test, we manually set up some stuff.
|
2004-08-12 12:35:13 +01:00
|
|
|
*
|
|
|
|
* But later, this will just iterate over all claims.
|
2004-08-11 12:22:20 +01:00
|
|
|
*/
|
|
|
|
int
|
2004-08-11 15:09:12 +01:00
|
|
|
arachne ()
|
2004-08-11 10:51:17 +01:00
|
|
|
{
|
2004-08-14 16:59:14 +01:00
|
|
|
Claimlist cl;
|
2004-08-12 12:35:13 +01:00
|
|
|
|
2004-08-13 21:56:51 +01:00
|
|
|
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");
|
2004-08-18 15:06:14 +01:00
|
|
|
return 1;
|
2004-08-13 21:56:51 +01:00
|
|
|
}
|
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
int determine_encrypt_max (Protocol p, Role r, Roledef rd, int index)
|
|
|
|
{
|
|
|
|
int tlevel;
|
2005-05-01 14:32:50 +01:00
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
tlevel = term_encryption_level (rd->message);
|
2005-04-18 06:51:25 +01:00
|
|
|
#ifdef DEBUG
|
2005-05-01 14:32:50 +01:00
|
|
|
if (DEBUGL (3))
|
2005-04-18 06:51:25 +01:00
|
|
|
{
|
|
|
|
eprintf ("Encryption level %i found for term ", tlevel);
|
|
|
|
termPrint (rd->message);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
#endif
|
2004-08-18 15:06:14 +01:00
|
|
|
if (tlevel > max_encryption_level)
|
|
|
|
max_encryption_level = tlevel;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-08-19 13:47:53 +01:00
|
|
|
/*
|
|
|
|
* set up claim role(s)
|
|
|
|
*/
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.runs == 0)
|
2004-08-27 19:26:19 +01:00
|
|
|
{
|
|
|
|
// No real checking.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-08-19 13:47:53 +01:00
|
|
|
if (sys->maxruns > 0)
|
|
|
|
{
|
|
|
|
error ("Something is wrong, number of runs >0.");
|
|
|
|
}
|
|
|
|
|
|
|
|
num_regular_runs = 0;
|
|
|
|
num_intruder_runs = 0;
|
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
max_encryption_level = 0;
|
2005-04-18 06:51:25 +01:00
|
|
|
iterate_role_events (determine_encrypt_max);
|
2004-08-14 17:12:32 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (1))
|
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
eprintf ("Maximum encryption level: %i\n", max_encryption_level);
|
2004-08-14 17:12:32 +01:00
|
|
|
}
|
|
|
|
#endif
|
2004-08-13 21:56:51 +01:00
|
|
|
|
2005-04-18 06:51:25 +01:00
|
|
|
fixAgentKeylevels ();
|
|
|
|
|
2004-08-13 12:11:59 +01:00
|
|
|
indentDepth = 0;
|
2004-10-14 16:25:28 +01:00
|
|
|
proofDepth = 0;
|
2004-08-14 16:59:14 +01:00
|
|
|
cl = sys->claimlist;
|
|
|
|
while (cl != NULL)
|
|
|
|
{
|
2004-08-15 17:44:54 +01:00
|
|
|
/**
|
|
|
|
* Check each claim
|
|
|
|
*/
|
2004-08-11 12:22:20 +01:00
|
|
|
|
2005-06-16 12:59:44 +01:00
|
|
|
// Skip the dummy claims
|
|
|
|
if (!isTermEqual (cl->type, CLAIM_Empty))
|
2004-08-14 17:12:32 +01:00
|
|
|
{
|
2005-06-16 12:59:44 +01:00
|
|
|
// Any other claims might be filterered
|
|
|
|
if (switches.filterClaim == NULL
|
|
|
|
|| switches.filterClaim == cl->type)
|
|
|
|
{
|
2005-12-27 13:44:12 +00:00
|
|
|
// Some claims are always true!
|
|
|
|
if (!cl->alwaystrue)
|
|
|
|
{
|
|
|
|
// others we simply test...
|
|
|
|
int run;
|
|
|
|
Protocol p;
|
|
|
|
Role r;
|
2004-08-19 13:47:53 +01:00
|
|
|
|
2005-12-27 13:44:12 +00:00
|
|
|
sys->current_claim = cl;
|
|
|
|
attack_length = INT_MAX;
|
|
|
|
attack_leastcost = INT_MAX;
|
|
|
|
cl->complete = 1;
|
|
|
|
p = (Protocol) cl->protocol;
|
|
|
|
r = (Role) cl->role;
|
2004-08-19 11:46:27 +01:00
|
|
|
|
2005-12-27 13:44:12 +00:00
|
|
|
if (switches.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++;
|
|
|
|
run = semiRunCreate (p, r);
|
|
|
|
proof_suppose_run (run, 0, cl->ev + 1);
|
|
|
|
add_read_goals (run, 0, cl->ev + 1);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add specific goal info
|
|
|
|
*/
|
2006-01-02 19:55:34 +00:00
|
|
|
add_claim_specifics (sys, cl,
|
2005-12-27 13:44:12 +00:00
|
|
|
roledef_shift (sys->runs[run].start,
|
|
|
|
cl->ev));
|
2005-12-27 10:49:22 +00:00
|
|
|
|
2004-08-14 16:59:14 +01:00
|
|
|
#ifdef DEBUG
|
2005-12-27 13:44:12 +00:00
|
|
|
if (DEBUGL (5))
|
|
|
|
{
|
|
|
|
printSemiState ();
|
|
|
|
}
|
2004-08-14 16:59:14 +01:00
|
|
|
#endif
|
2005-12-27 13:44:12 +00:00
|
|
|
iterate_buffer_attacks ();
|
2004-08-14 16:59:14 +01:00
|
|
|
|
2005-12-27 13:44:12 +00:00
|
|
|
//! Destroy
|
|
|
|
while (sys->bindings != NULL)
|
|
|
|
{
|
|
|
|
goal_remove_last (1);
|
|
|
|
}
|
|
|
|
while (sys->maxruns > 0)
|
|
|
|
{
|
|
|
|
semiRunDestroy ();
|
|
|
|
}
|
2005-05-19 15:43:32 +01:00
|
|
|
|
2005-12-27 13:44:12 +00:00
|
|
|
//! Indent back
|
|
|
|
indentDepth--;
|
2005-05-19 15:43:32 +01:00
|
|
|
|
2005-12-27 13:44:12 +00:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Proof complete for this claim.\n");
|
|
|
|
}
|
2005-06-16 12:59:44 +01:00
|
|
|
}
|
2005-05-19 15:43:32 +01:00
|
|
|
}
|
2004-08-14 20:19:23 +01:00
|
|
|
}
|
2004-08-14 16:59:14 +01:00
|
|
|
// next
|
|
|
|
cl = cl->next;
|
|
|
|
}
|
2004-08-11 10:51:17 +01:00
|
|
|
}
|
2005-08-12 13:13:50 +01:00
|
|
|
|
|
|
|
//! Construct knowledge set at some event, based on a semitrace.
|
|
|
|
/**
|
|
|
|
* This is a very 'stupid' algorithm; it is just there because GijsH
|
|
|
|
* requested it. It does in no way guarantee that this is the actual
|
|
|
|
* knowledge set at the given point. It simply gives an underapproximation,
|
|
|
|
* that will be correct in most cases. The main reason for this is that it
|
|
|
|
* completely ignores any information on unbound variables, and regards them
|
|
|
|
* as bound constants.
|
|
|
|
*
|
|
|
|
* Because everything is supposed to be bound, we conclude that even 'read'
|
|
|
|
* events imply a certain knowledge.
|
|
|
|
*
|
|
|
|
* If aftercomplete is 0 or false, we actually check the ordering; otherwise we
|
|
|
|
* just assume the trace has finished.
|
|
|
|
*
|
|
|
|
* Use knowledgeDelete later to clean up.
|
|
|
|
*/
|
|
|
|
Knowledge
|
|
|
|
knowledgeAtArachne (const System sys, const int myrun, const int myindex,
|
|
|
|
const int aftercomplete)
|
|
|
|
{
|
|
|
|
Knowledge know;
|
|
|
|
int run;
|
|
|
|
|
|
|
|
know = knowledgeDuplicate (sys->know); // duplicate initial knowledge
|
|
|
|
run = 0;
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
int index;
|
2006-01-02 21:06:08 +00:00
|
|
|
int maxheight;
|
2005-08-12 13:13:50 +01:00
|
|
|
Roledef rd;
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
rd = sys->runs[run].start;
|
2006-01-02 21:06:08 +00:00
|
|
|
maxheight = sys->runs[run].height;
|
|
|
|
if (run == myrun && myindex > maxheight)
|
2005-08-12 13:13:50 +01:00
|
|
|
{
|
|
|
|
// local run index can override real step
|
2006-01-02 21:06:08 +00:00
|
|
|
maxheight = myindex;
|
2005-08-12 13:13:50 +01:00
|
|
|
}
|
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
while (rd != NULL && index < maxheight)
|
2005-08-12 13:13:50 +01:00
|
|
|
{
|
|
|
|
// Check whether this event precedes myevent
|
2006-02-26 15:00:58 +00:00
|
|
|
if (aftercomplete || isDependEvent (run, index, myrun, myindex))
|
2005-08-12 13:13:50 +01:00
|
|
|
{
|
|
|
|
// If it is a send (trivial) or a read (remarkable, but true
|
|
|
|
// because of bindings) we can add the message and the agents to
|
|
|
|
// the knowledge.
|
|
|
|
if (rd->type == SEND || rd->type == READ)
|
|
|
|
{
|
|
|
|
knowledgeAddTerm (know, rd->message);
|
|
|
|
if (rd->from != NULL)
|
|
|
|
knowledgeAddTerm (know, rd->from);
|
|
|
|
if (rd->to != NULL)
|
|
|
|
knowledgeAddTerm (know, rd->to);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
rd = rd->next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Not ordered before anymore, so we skip to the next run.
|
|
|
|
rd = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
return know;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Determine whether a term is trivially known at some event in a partially ordered structure.
|
|
|
|
/**
|
|
|
|
* Important: read disclaimer at knowledgeAtArachne()
|
|
|
|
*
|
|
|
|
* Returns true iff the term is certainly known at that point in the
|
|
|
|
* semitrace.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
isTriviallyKnownAtArachne (const System sys, const Term t, const int run,
|
|
|
|
const int index)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
Knowledge knowset;
|
|
|
|
|
|
|
|
knowset = knowledgeAtArachne (sys, run, index, false);
|
|
|
|
result = inKnowledge (knowset, t);
|
|
|
|
knowledgeDelete (knowset);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Determine whether a term is trivially known after execution of some partially ordered structure.
|
|
|
|
/**
|
|
|
|
* Important: read disclaimer at knowledgeAtArachne()
|
|
|
|
*
|
|
|
|
* Returns true iff the term is certainly known after all events in the
|
|
|
|
* semitrace.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
isTriviallyKnownAfterArachne (const System sys, const Term t, const int run,
|
|
|
|
const int index)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
Knowledge knowset;
|
|
|
|
|
|
|
|
knowset = knowledgeAtArachne (sys, run, index, true);
|
|
|
|
result = inKnowledge (knowset, t);
|
|
|
|
knowledgeDelete (knowset);
|
|
|
|
return result;
|
|
|
|
}
|