2007-06-11 13:01:04 +01:00
|
|
|
/*
|
|
|
|
* Scyther : An automatic verifier for security protocols.
|
|
|
|
* Copyright (C) 2007 Cas Cremers
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2006-01-02 18:43:25 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*@file prune_bounds.c
|
|
|
|
*
|
|
|
|
* Prune stuff based on bounds
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#include "termlist.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "switches.h"
|
2007-01-06 14:45:29 +00:00
|
|
|
#include "timer.h"
|
|
|
|
#include "arachne.h"
|
|
|
|
#include "system.h"
|
2007-01-26 15:31:49 +00:00
|
|
|
#include "termmap.h"
|
2007-01-06 14:45:29 +00:00
|
|
|
#include "cost.h"
|
2006-01-02 18:43:25 +00:00
|
|
|
|
|
|
|
extern int attack_length;
|
|
|
|
extern int attack_leastcost;
|
|
|
|
extern Protocol INTRUDER;
|
|
|
|
extern int proofDepth;
|
|
|
|
extern int max_encryption_level;
|
|
|
|
|
2007-01-26 15:31:49 +00:00
|
|
|
//! Forward declarations
|
|
|
|
int tooManyOfRole (const System sys);
|
|
|
|
|
2006-01-02 18:43:25 +00:00
|
|
|
//! Prune determination for bounds
|
|
|
|
/**
|
|
|
|
* When something is pruned here, the state space is not complete anymore.
|
|
|
|
*
|
|
|
|
*@returns true iff this state is invalid for some reason
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
prune_bounds (const System sys)
|
|
|
|
{
|
|
|
|
/* prune for time */
|
|
|
|
if (passed_time_limit ())
|
|
|
|
{
|
|
|
|
// Oh no, we ran out of time!
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Pruned: ran out of allowed time (-T %i switch)\n",
|
|
|
|
get_time_limit ());
|
|
|
|
}
|
|
|
|
// Pruned because of time bound!
|
|
|
|
sys->current_claim->timebound = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-11-23 10:40:10 +00:00
|
|
|
/* prune for number of attacks if we are actually outputting them */
|
2006-08-15 09:16:02 +01:00
|
|
|
if (enoughAttacks (sys))
|
|
|
|
{
|
2006-11-23 10:40:10 +00:00
|
|
|
// Oh no, we ran out of possible attacks!
|
2006-08-15 09:16:02 +01:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("Pruned: we already found the maximum number of attacks.\n");
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-01-02 18:43:25 +00:00
|
|
|
/* prune for proof depth */
|
|
|
|
if (proofDepth > switches.maxproofdepth)
|
|
|
|
{
|
|
|
|
// Hardcoded limit on proof tree depth
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Pruned: proof tree too deep: %i (-d %i switch)\n",
|
|
|
|
proofDepth, switches.maxproofdepth);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* prune for trace length */
|
|
|
|
if (switches.maxtracelength < INT_MAX)
|
|
|
|
{
|
|
|
|
int tracelength;
|
|
|
|
int run;
|
|
|
|
|
|
|
|
/* compute trace length of current semistate */
|
|
|
|
tracelength = 0;
|
|
|
|
run = 0;
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
/* ignore intruder actions */
|
|
|
|
if (sys->runs[run].protocol != INTRUDER)
|
|
|
|
{
|
|
|
|
tracelength = tracelength + sys->runs[run].step;
|
|
|
|
}
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
/* test */
|
|
|
|
if (tracelength > switches.maxtracelength)
|
|
|
|
{
|
|
|
|
// Hardcoded limit on proof tree depth
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Pruned: trace too long: %i (-l %i switch)\n",
|
|
|
|
tracelength, switches.maxtracelength);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-26 15:31:49 +00:00
|
|
|
/* prune for runs */
|
2006-04-02 13:29:02 +01:00
|
|
|
if (sys->num_regular_runs > switches.runs)
|
2006-01-02 18:43:25 +00:00
|
|
|
{
|
|
|
|
// Hardcoded limit on runs
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
2006-04-02 13:29:02 +01:00
|
|
|
eprintf ("Pruned: too many regular runs (%i).\n",
|
|
|
|
sys->num_regular_runs);
|
2006-01-02 18:43:25 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-01-26 15:31:49 +00:00
|
|
|
/* prune for role instances max */
|
|
|
|
if (tooManyOfRole (sys))
|
|
|
|
{
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Pruned: too many instances of a particular role.\n");
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-01-02 18:43:25 +00:00
|
|
|
// This needs some foundation. Probably * 2^max_encryption_level
|
2006-02-22 08:24:29 +00:00
|
|
|
//!@todo Remove later
|
|
|
|
/**
|
|
|
|
* This should be removed once the hidelevel lemma works correctly
|
|
|
|
*/
|
2006-02-28 15:01:58 +00:00
|
|
|
if (switches.experimental & 1)
|
2006-01-02 18:43:25 +00:00
|
|
|
{
|
2006-02-22 09:53:50 +00:00
|
|
|
if ((switches.match < 2)
|
2006-04-02 13:29:02 +01:00
|
|
|
&& (sys->num_intruder_runs >
|
2006-02-22 09:53:50 +00:00
|
|
|
((double) switches.runs * max_encryption_level * 8)))
|
2006-01-02 18:43:25 +00:00
|
|
|
{
|
2006-02-22 09:53:50 +00:00
|
|
|
// Hardcoded limit on iterations
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("Pruned: %i intruder runs is too much. (max encr. level %i)\n",
|
2006-04-02 13:29:02 +01:00
|
|
|
sys->num_intruder_runs, max_encryption_level);
|
2006-02-22 09:53:50 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2006-01-02 18:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Limit on exceeding any attack length
|
|
|
|
if (get_semitrace_length () >= attack_length)
|
|
|
|
{
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Pruned: attack length %i.\n", attack_length);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* prune for cheaper */
|
2006-07-06 16:52:13 +01:00
|
|
|
if (switches.prune != 0 && attack_leastcost <= attackCost (sys))
|
2006-01-02 18:43:25 +00:00
|
|
|
{
|
|
|
|
// We already had an attack at least this cheap.
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("Pruned: attack cost exceeds a previously found attack.\n");
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Limit on attack count
|
|
|
|
if (enoughAttacks (sys))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
// Pruning involving the number of intruder actions
|
|
|
|
{
|
|
|
|
// Count intruder actions
|
|
|
|
int actioncount;
|
|
|
|
|
|
|
|
actioncount = countIntruderActions ();
|
|
|
|
|
|
|
|
// Limit intruder actions in any case
|
2006-03-10 14:52:45 +00:00
|
|
|
if (!switches.intruder)
|
2006-01-02 18:43:25 +00:00
|
|
|
{
|
2006-03-10 14:52:45 +00:00
|
|
|
if (actioncount > 0)
|
2006-01-02 18:43:25 +00:00
|
|
|
{
|
2006-03-10 14:52:45 +00:00
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("Pruned: no intruder allowed.\n",
|
|
|
|
switches.maxIntruderActions);
|
|
|
|
}
|
|
|
|
return 1;
|
2006-01-02 18:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Limit on intruder events count
|
|
|
|
if (actioncount > switches.maxIntruderActions)
|
|
|
|
{
|
|
|
|
if (switches.output == PROOF)
|
|
|
|
{
|
|
|
|
indentPrint ();
|
|
|
|
eprintf
|
|
|
|
("Pruned: more than %i encrypt/decrypt events in the semitrace.\n",
|
|
|
|
switches.maxIntruderActions);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No pruning because of bounds
|
|
|
|
return 0;
|
|
|
|
}
|
2007-01-26 15:31:49 +00:00
|
|
|
|
|
|
|
//! Detect when there are too many instances of a certain role
|
|
|
|
int
|
|
|
|
tooManyOfRole (const System sys)
|
|
|
|
{
|
|
|
|
int toomany;
|
|
|
|
|
|
|
|
toomany = false;
|
|
|
|
if (switches.maxOfRole > 0)
|
|
|
|
{
|
|
|
|
Termmap f;
|
|
|
|
int run;
|
|
|
|
|
|
|
|
f = NULL;
|
|
|
|
for (run = 0; run < sys->maxruns; run++)
|
|
|
|
{
|
|
|
|
if (sys->runs[run].protocol != INTRUDER)
|
|
|
|
{
|
|
|
|
// maybe this conflicts with equal protocols...? TODO
|
|
|
|
Term role;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
role = sys->runs[run].role->nameterm;
|
|
|
|
count = termmapGet (f, role);
|
|
|
|
if (count == -1)
|
|
|
|
count = 1;
|
|
|
|
else
|
|
|
|
count++;
|
|
|
|
f = termmapSet (f, role, count);
|
|
|
|
if (count > switches.maxOfRole)
|
|
|
|
{
|
|
|
|
toomany = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
termmapDelete (f);
|
|
|
|
}
|
|
|
|
return toomany;
|
|
|
|
}
|