Attack output improvement: better choice of agent names.
When an attack pattern is displayed, Scyther instantiates open variables with concrete names. This is often more intuitive for humans. In the case of instantiating role names, we often ended up assigning Alice to the B role and Bob to the A role. This patch provides a more clever heuristic to find agent names that start with the same letter as the role (variable) name. In case this fails, we still try to map Alice to roles starting with 'I' and Bob to 'R', and otherwise we just pick something. Also added "Simon" and "Pete" to cover some common role names. Conflicts: src/arachne.c
This commit is contained in:
parent
e966bc88dd
commit
b0e5128e23
152
src/arachne.c
152
src/arachne.c
@ -1734,53 +1734,148 @@ findUsedConstants (const System sys)
|
||||
return tlconst;
|
||||
}
|
||||
|
||||
//! Retrieve a list of agent name candidates
|
||||
Termlist
|
||||
getAgentCandidates (Termlist seen)
|
||||
{
|
||||
Termlist knowlist;
|
||||
Termlist candidatelist;
|
||||
Termlist li; // list loop pointer
|
||||
|
||||
knowlist = knowledgeSet (sys->know);
|
||||
candidatelist = NULL;
|
||||
for (li = knowlist; li != NULL; li = li->next)
|
||||
{
|
||||
Term t;
|
||||
|
||||
t = li->term;
|
||||
if (isAgentType (t->stype))
|
||||
{
|
||||
/* agent */
|
||||
/* We don'typeterm want to instantiate untrusted agents. */
|
||||
if (!inTermlist (sys->untrusted, t))
|
||||
{
|
||||
/* trusted agent */
|
||||
if (!inTermlist (seen, t))
|
||||
{
|
||||
/* This agent name is not in the list yet, so could be chosen */
|
||||
candidatelist = termlistPrepend (candidatelist, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
termlistDelete (knowlist);
|
||||
return candidatelist;
|
||||
}
|
||||
|
||||
//! Get to string of term
|
||||
const char *
|
||||
getTermString (Term t)
|
||||
{
|
||||
if (t != NULL)
|
||||
{
|
||||
if (TermSymb (t) != NULL)
|
||||
{
|
||||
return (TermSymb (t)->text);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Check the first character of two terms
|
||||
int
|
||||
isFirstCharEqual (Term t1, Term t2)
|
||||
{
|
||||
const char *c1, *c2;
|
||||
|
||||
c1 = getTermString (t1);
|
||||
c2 = getTermString (t2);
|
||||
if ((c1 == NULL) || (c2 == NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (c1[0] == c2[0]);
|
||||
}
|
||||
}
|
||||
|
||||
//! Choose the best term from the (non-null) candidate list for the variable var
|
||||
Term
|
||||
chooseBestCandidate (Termlist candidatelist, Term var)
|
||||
{
|
||||
Term last;
|
||||
Termlist li; // list loop pointer
|
||||
|
||||
// See if we have a candidate that starts with the same first character
|
||||
for (li = candidatelist; li != NULL; li = li->next)
|
||||
{
|
||||
last = li->term;
|
||||
if (isFirstCharEqual (last, var))
|
||||
{
|
||||
return last;
|
||||
}
|
||||
}
|
||||
// If not, we may still want to invoke heuristics (Alice initiates, Bob responds)
|
||||
if (li == NULL)
|
||||
{
|
||||
// li==null happens if we did not break out of the loop, i.e., found nothing
|
||||
const char *c;
|
||||
|
||||
c = getTermString (var);
|
||||
if (c != NULL)
|
||||
{
|
||||
// Check if name starts with common prefix, resort to common name if still a candidate
|
||||
if (strchr ("Ii", *c) && inTermlist (candidatelist, AGENT_Alice))
|
||||
{
|
||||
return AGENT_Alice;
|
||||
}
|
||||
if (strchr ("Rr", *c) && inTermlist (candidatelist, AGENT_Bob))
|
||||
{
|
||||
return AGENT_Bob;
|
||||
}
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
//! Create a new term with incremented run rumber, starting at sys->maxruns.
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Output: the first element of the returned list.
|
||||
* Input:
|
||||
* - seen is a termlist that contains newly generated terms (usage: seen = createNewTerm(seen,.. )
|
||||
* - typeterm is the type name term (e.g., "Agent" term, "Data" in case not clear.)
|
||||
* - isagent is a boolean that is true iff we are looking for an agent name from the initial knowledge for a role
|
||||
* - var is the variable term
|
||||
*
|
||||
* Output: the first element of the returned list, which is otherwise equal to seen.
|
||||
*/
|
||||
Termlist
|
||||
createNewTerm (Termlist tl, Term t, int isagent)
|
||||
createNewTerm (Termlist seen, Term typeterm, int isagent, Term var)
|
||||
{
|
||||
/* 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;
|
||||
Termlist candidatelist;
|
||||
|
||||
knowlist = knowledgeSet (sys->know);
|
||||
kl = knowlist;
|
||||
while (kl != NULL)
|
||||
candidatelist = getAgentCandidates (seen);
|
||||
if (candidatelist != NULL)
|
||||
{
|
||||
Term k;
|
||||
Term t;
|
||||
|
||||
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);
|
||||
t = chooseBestCandidate (candidatelist, var);
|
||||
termlistDelete (candidatelist);
|
||||
return termlistPrepend (seen, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
kl = kl->next;
|
||||
}
|
||||
termlistDelete (knowlist);
|
||||
}
|
||||
|
||||
/* Not an agent or no free one found */
|
||||
return createNewTermGeneric (tl, t);
|
||||
return createNewTermGeneric (seen, typeterm);
|
||||
}
|
||||
|
||||
//! Delete a term made in the previous constructions
|
||||
@ -1802,7 +1897,7 @@ deleteNewTerm (Term t)
|
||||
//! Make a trace concrete
|
||||
/**
|
||||
* People find reading variables in attack outputs difficult.
|
||||
* Thus, we instantiate them in a sensible way to make things more readable.
|
||||
* Thus, we instantiate open variables in a sensible way to make things more readable.
|
||||
*
|
||||
* This happens after sys->maxruns is fixed. Intruder constants thus are numbered from sys->maxruns onwards.
|
||||
*
|
||||
@ -1847,7 +1942,8 @@ makeTraceConcrete (const System sys)
|
||||
name = TERM_Data;
|
||||
}
|
||||
// We should turn this into an actual term
|
||||
tlnew = createNewTerm (tlnew, name, isAgentType (var->stype));
|
||||
tlnew =
|
||||
createNewTerm (tlnew, name, isAgentType (var->stype), var);
|
||||
var->subst = tlnew->term;
|
||||
|
||||
// Store for undo later
|
||||
|
@ -68,6 +68,8 @@ Term AGENT_Bob;
|
||||
Term AGENT_Charlie;
|
||||
Term AGENT_Dave;
|
||||
Term AGENT_Eve;
|
||||
Term AGENT_Simon;
|
||||
Term AGENT_Pete;
|
||||
Term TERM_PK;
|
||||
Term TERM_SK;
|
||||
Term TERM_K;
|
||||
@ -144,12 +146,16 @@ specialTermInitAfter (const System sys)
|
||||
langcons (AGENT_Charlie, "Charlie", TERM_Agent);
|
||||
langcons (AGENT_Dave, "Dave", TERM_Agent);
|
||||
langcons (AGENT_Eve, "Eve", TERM_Agent);
|
||||
langcons (AGENT_Simon, "Simon", TERM_Agent);
|
||||
langcons (AGENT_Pete, "Pete", TERM_Agent);
|
||||
|
||||
knowledgeAddTerm (sys->know, AGENT_Alice);
|
||||
knowledgeAddTerm (sys->know, AGENT_Bob);
|
||||
knowledgeAddTerm (sys->know, AGENT_Charlie);
|
||||
knowledgeAddTerm (sys->know, AGENT_Dave);
|
||||
knowledgeAddTerm (sys->know, AGENT_Eve);
|
||||
knowledgeAddTerm (sys->know, AGENT_Simon);
|
||||
knowledgeAddTerm (sys->know, AGENT_Pete);
|
||||
|
||||
// Make special Eve keys and add to initial knowledge
|
||||
SKE = makeTermEncrypt (AGENT_Eve, TERM_SK);
|
||||
|
@ -60,6 +60,8 @@ extern Term AGENT_Bob;
|
||||
extern Term AGENT_Charlie;
|
||||
extern Term AGENT_Dave;
|
||||
extern Term AGENT_Eve;
|
||||
extern Term AGENT_Simon;
|
||||
extern Term AGENT_Pete;
|
||||
extern Term TERM_PK;
|
||||
extern Term TERM_SK;
|
||||
extern Term TERM_K;
|
||||
|
Loading…
Reference in New Issue
Block a user