2004-11-18 14:47:44 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
2004-11-19 09:53:51 +00:00
|
|
|
# Multi-protocol test using Scyther
|
|
|
|
#
|
|
|
|
# (c)2004 Cas Cremers
|
2004-11-18 14:47:44 +00:00
|
|
|
#
|
|
|
|
# Input of this script:
|
|
|
|
#
|
|
|
|
# - A number on the commandline of stuff to test
|
|
|
|
# - A list of files on stdin to be used
|
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
# ***********************
|
|
|
|
# PARAMETERS
|
|
|
|
# ***********************
|
2004-11-18 14:47:44 +00:00
|
|
|
|
|
|
|
TempFileList = "scyther-blap.tmp"
|
|
|
|
TempFileTuples = "scyther-blip.tmp"
|
|
|
|
|
|
|
|
TupleProgram = "./tuples.py"
|
|
|
|
|
|
|
|
ScytherProgram = "../src/scyther"
|
|
|
|
ScytherDefaults = "--summary"
|
2004-11-18 15:50:54 +00:00
|
|
|
ScytherMethods = "-m0 -a"
|
2004-11-18 14:47:44 +00:00
|
|
|
ScytherBounds = "-r4 -l40"
|
|
|
|
|
2004-11-18 15:06:41 +00:00
|
|
|
ReportInterval = 10
|
|
|
|
|
2004-11-18 14:47:44 +00:00
|
|
|
ScytherArgs = ScytherDefaults + " " + ScytherMethods + " " + ScytherBounds
|
|
|
|
CommandPrefix = ScytherProgram + " " + ScytherArgs
|
|
|
|
|
|
|
|
ProtocolClaims = {}
|
2004-11-19 09:53:51 +00:00
|
|
|
ProtocolFiles = {}
|
2004-11-18 14:47:44 +00:00
|
|
|
|
2004-11-18 15:50:54 +00:00
|
|
|
SkipList = [
|
|
|
|
'gong-nonce.spdl',
|
|
|
|
'gong-nonce-b.spdl',
|
|
|
|
'splice-as-hc.spdl',
|
|
|
|
'kaochow-palm.spdl'
|
|
|
|
]
|
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
# ***********************
|
|
|
|
# MODULES
|
|
|
|
# ***********************
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import string
|
|
|
|
import commands
|
|
|
|
|
2004-11-18 14:47:44 +00:00
|
|
|
# ***********************
|
|
|
|
# LIBS
|
|
|
|
# ***********************
|
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
# GetKeys
|
|
|
|
#
|
|
|
|
# Given a mapping f and a value x, returns a list of keys
|
|
|
|
# k for which f(k) = x
|
|
|
|
def GetKeys (f, x):
|
|
|
|
res = []
|
|
|
|
for k in f.keys():
|
|
|
|
if f[k] == x:
|
|
|
|
res.append(k)
|
|
|
|
return res
|
|
|
|
|
2004-11-18 16:18:23 +00:00
|
|
|
# CommandLine
|
|
|
|
#
|
|
|
|
# Yield the commandline to test, given a list of protocols
|
|
|
|
def CommandLine (plist):
|
|
|
|
linelist = " ".join(plist)
|
|
|
|
return "cat " + linelist + " | " + CommandPrefix
|
|
|
|
|
|
|
|
|
2004-11-18 14:47:44 +00:00
|
|
|
# ScytherEval
|
|
|
|
#
|
|
|
|
# Take the list of protocols in plist, and give them to Scyther.
|
|
|
|
# Returns a dictionary of claim -> bool; where 1 means that it is
|
|
|
|
# correct, and 0 means that it is false (i.e. there exists an attack)
|
|
|
|
def ScytherEval (plist):
|
2004-11-18 16:18:23 +00:00
|
|
|
scout = commands.getoutput(CommandLine (plist))
|
2004-11-18 14:47:44 +00:00
|
|
|
lines = scout.splitlines()
|
|
|
|
results = {}
|
|
|
|
for line in lines:
|
|
|
|
data = line.split()
|
2004-11-18 15:50:54 +00:00
|
|
|
if len(data) > 6 and data[0] == 'claim':
|
2004-11-18 14:47:44 +00:00
|
|
|
claim = " ".join(data[1:4])
|
|
|
|
tag = data[6]
|
|
|
|
value = -1
|
|
|
|
if tag == 'failed:':
|
|
|
|
value = 0
|
|
|
|
if tag == 'correct:':
|
|
|
|
value = 1
|
|
|
|
if value == -1:
|
2004-11-18 16:07:58 +00:00
|
|
|
raise IOError, 'Scyther output for ' + commandline + ', line ' + line + ' cannot be parsed.'
|
2004-11-18 14:47:44 +00:00
|
|
|
results[claim] = value
|
|
|
|
return results
|
|
|
|
|
|
|
|
# ScytherEval1
|
|
|
|
#
|
|
|
|
# The above, but do the preprocessing for a single protocol
|
|
|
|
def ScytherEval1 (protocol):
|
2004-11-18 15:06:41 +00:00
|
|
|
results = ScytherEval ([protocol])
|
2004-11-19 09:53:51 +00:00
|
|
|
|
|
|
|
# Add the claim to the list of ProtocolClaims
|
2004-11-18 16:07:58 +00:00
|
|
|
for claim in results.keys():
|
|
|
|
if ProtocolClaims.has_key(claim):
|
2004-11-19 09:53:51 +00:00
|
|
|
# Claim occurs in two protocols; determine the
|
|
|
|
# files
|
|
|
|
file1 = ProtocolFiles[claim.split()[0]]
|
|
|
|
file2 = protocol
|
|
|
|
raise IOError, 'Claim occurs in two protocols: ' + claim + ", in files (" + file1 + ") and (" + file2 + ")"
|
2004-11-18 14:47:44 +00:00
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
# Add the filename to the protocol mappings
|
|
|
|
prname = claim.split()[0]
|
|
|
|
ProtocolFiles[prname] = protocol
|
2004-11-18 14:47:44 +00:00
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
ProtocolClaims.update (results)
|
2004-11-18 14:47:44 +00:00
|
|
|
|
2004-11-18 15:50:54 +00:00
|
|
|
# Show progress of i (0..n)
|
|
|
|
#
|
|
|
|
LastProgress = {}
|
|
|
|
ProgressBarWidth = 50
|
|
|
|
|
|
|
|
def ShowProgress (i,n,txt):
|
|
|
|
factor = int((ProgressBarWidth * i) / n)
|
|
|
|
showme = 0
|
|
|
|
if LastProgress.has_key(n):
|
|
|
|
if LastProgress[n]<>(factor,txt):
|
|
|
|
showme = 1
|
|
|
|
else:
|
|
|
|
showme = 1
|
|
|
|
if showme == 1:
|
|
|
|
bar = "\r["
|
|
|
|
i = 0
|
|
|
|
while i < ProgressBarWidth:
|
|
|
|
if i <= factor:
|
|
|
|
bar = bar + "*"
|
|
|
|
else:
|
|
|
|
bar = bar + "."
|
|
|
|
i = i+1
|
|
|
|
bar = bar + "] " + txt
|
2004-11-19 10:13:08 +00:00
|
|
|
sys.stderr.write(bar)
|
|
|
|
sys.stderr.flush()
|
2004-11-18 15:50:54 +00:00
|
|
|
LastProgress[n] = (factor, txt)
|
|
|
|
|
|
|
|
def ClearProgress (n,txt):
|
|
|
|
bar = " " * (1 + ProgressBarWidth + 2 + len(txt))
|
2004-11-19 10:13:08 +00:00
|
|
|
sys.stderr.write("\r" + bar + "\r")
|
|
|
|
sys.stderr.flush()
|
2004-11-18 15:50:54 +00:00
|
|
|
|
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
def DescribeContext (filep, protocols, claim):
|
|
|
|
def DC_Claim(cl,v):
|
|
|
|
if v == 0:
|
|
|
|
filep.write ("- " + cl + " : false in isolation")
|
|
|
|
elif v == 1:
|
|
|
|
filep.write ("+ " + cl + " : correct in isolation")
|
|
|
|
elif v == 2:
|
|
|
|
filep.write ("* " + cl + " : newly false in multi-protocol test")
|
|
|
|
else:
|
|
|
|
filep.write ("???")
|
|
|
|
filep.write ("\n")
|
|
|
|
|
|
|
|
filep.write ("-- Attack description.\n\n")
|
|
|
|
filep.write ("Involving the protocols:\n")
|
|
|
|
|
|
|
|
for prfile in protocols:
|
|
|
|
prnames = GetKeys (ProtocolFiles, prfile)
|
|
|
|
filep.write ("- " + prfile + ": " + ",".join(prnames) + "\n")
|
|
|
|
newprname = claim.split()[0]
|
|
|
|
newprfile = ProtocolFiles[newprname]
|
|
|
|
filep.write ("The new attack occurs in " + newprfile + ": " + newprname)
|
|
|
|
|
|
|
|
filep.write ("\n\n")
|
|
|
|
filep.write (" $ " + CommandLine (protocols) + "\n")
|
|
|
|
filep.write ("\n")
|
|
|
|
DC_Claim (claim, 2)
|
|
|
|
|
|
|
|
# Determine, for each protocol name within the list of files,
|
|
|
|
# which claims fall under it, and show their previous status
|
|
|
|
|
|
|
|
for prname in ProtocolFiles:
|
|
|
|
# Protocol name
|
|
|
|
if ProtocolFiles[prname] in protocols:
|
|
|
|
# prname is a protocol name within the scope
|
|
|
|
# first print isolation correct files (skipping
|
|
|
|
# the claim one, because that is obvious)
|
2004-11-18 15:50:54 +00:00
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
cllist = []
|
|
|
|
for cl in ProtocolClaims.keys():
|
|
|
|
if cl.split()[0] == prname:
|
|
|
|
cllist.append( (cl,ProtocolClaims[cl]) )
|
2004-11-18 15:50:54 +00:00
|
|
|
|
2004-11-19 09:53:51 +00:00
|
|
|
for cl,v in cllist:
|
|
|
|
if v == 1 and cl <> claim:
|
|
|
|
DC_Claim(cl,1)
|
|
|
|
for cl,v in cllist:
|
|
|
|
if v == 0 and cl <> claim:
|
|
|
|
DC_Claim(cl,0)
|
|
|
|
filep.write ("\n")
|
2004-11-18 15:50:54 +00:00
|
|
|
|
|
|
|
|
2004-11-18 14:47:44 +00:00
|
|
|
|
|
|
|
# ***********************
|
|
|
|
# MAIN CODE
|
|
|
|
# ***********************
|
|
|
|
|
|
|
|
# Pass std input to temporary file (list of protocol files)
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# Determines:
|
|
|
|
# TupleWidth
|
|
|
|
# ProtocolCount
|
|
|
|
# Protocol[0..count-1]
|
|
|
|
#
|
|
|
|
# Furthermore, TempFileList is created.
|
|
|
|
|
|
|
|
TupleWidth = sys.argv[1]
|
|
|
|
|
|
|
|
# Read stdin into list and count, send to file
|
|
|
|
loop = 1
|
|
|
|
ProtocolCount = 0
|
|
|
|
Protocol = []
|
|
|
|
outp = open(TempFileList, 'w')
|
|
|
|
while loop:
|
|
|
|
line = sys.stdin.readline()
|
|
|
|
if line != '':
|
|
|
|
# not the end of the input
|
|
|
|
cleanline = string.strip(line)
|
2004-11-18 15:50:54 +00:00
|
|
|
if cleanline != '' and cleanline not in SkipList:
|
|
|
|
# not a blank line, not forbidden
|
2004-11-18 14:47:44 +00:00
|
|
|
Protocol.append(cleanline)
|
|
|
|
ProtocolCount = ProtocolCount + 1
|
|
|
|
outp.write(line)
|
|
|
|
else:
|
|
|
|
# end of the input
|
|
|
|
loop = 0
|
|
|
|
outp.close()
|
|
|
|
|
|
|
|
# Caching of single-protocol results for speed gain.
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# The script first computes the singular results for all the protocols
|
|
|
|
# and stores this in an array, or something like that.
|
|
|
|
|
2004-11-18 15:50:54 +00:00
|
|
|
print "Evaluating tuples of", TupleWidth, "for", ProtocolCount, "protocols, using the command '" + CommandPrefix + "'"
|
2004-11-18 14:47:44 +00:00
|
|
|
i = 0
|
2004-11-18 15:50:54 +00:00
|
|
|
safetxt = ' '
|
2004-11-18 14:47:44 +00:00
|
|
|
while i < ProtocolCount:
|
2004-11-18 15:50:54 +00:00
|
|
|
ShowProgress (i, ProtocolCount,Protocol[i]+safetxt)
|
2004-11-18 14:47:44 +00:00
|
|
|
ScytherEval1 ( Protocol[i] )
|
|
|
|
i = i + 1
|
2004-11-18 15:50:54 +00:00
|
|
|
ClearProgress(ProtocolCount, safetxt)
|
2004-11-18 16:14:31 +00:00
|
|
|
print "Evaluated single results."
|
2004-11-18 14:47:44 +00:00
|
|
|
|
|
|
|
# Computation of combined list.
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# We use the tuple script to generate the list of tuples we need.
|
|
|
|
# We use a temporary file (again) to store that list.
|
|
|
|
# This requires that 'tuples.py' is in the same directory.
|
|
|
|
|
|
|
|
lstatus=os.system(TupleProgram + ' ' + TupleWidth + ' <' + TempFileList + ' >' + TempFileTuples)
|
|
|
|
|
2004-11-18 15:50:54 +00:00
|
|
|
inp = open(TempFileTuples, 'r')
|
|
|
|
TupleCount = 0
|
|
|
|
for x in inp:
|
|
|
|
TupleCount = TupleCount + 1
|
|
|
|
inp.close()
|
2004-11-18 16:14:31 +00:00
|
|
|
print "Commencing test for", TupleCount, "protocol combinations."
|
2004-11-18 15:50:54 +00:00
|
|
|
|
2004-11-18 14:47:44 +00:00
|
|
|
# Testing of protocol tuples
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# We take the list of tuples and test each combination.
|
|
|
|
|
2004-11-18 15:06:41 +00:00
|
|
|
inp = open(TempFileTuples, 'r')
|
|
|
|
processed = 0
|
|
|
|
newattacks = 0
|
|
|
|
for tline in inp:
|
|
|
|
#
|
|
|
|
# Get the next tuple
|
|
|
|
#
|
|
|
|
protocols = tline.split()
|
2004-11-18 15:50:54 +00:00
|
|
|
ShowProgress (processed, TupleCount, " ".join(protocols) + safetxt)
|
|
|
|
#
|
|
|
|
# Process it
|
|
|
|
#
|
2004-11-18 15:06:41 +00:00
|
|
|
results = ScytherEval ( protocols )
|
|
|
|
#
|
|
|
|
# Now we have the results for this combination.
|
|
|
|
# Check whether any of these claims is 'newly false'
|
|
|
|
#
|
|
|
|
for claim,value in results.items():
|
|
|
|
if value == 0:
|
|
|
|
# Apparently this claim is false now (there is
|
|
|
|
# an attack)
|
|
|
|
if ProtocolClaims[claim] == 1:
|
|
|
|
# Wooh! It was correct before
|
2004-11-18 15:50:54 +00:00
|
|
|
ClearProgress (TupleCount, safetxt)
|
2004-11-18 15:06:41 +00:00
|
|
|
newattacks = newattacks + 1
|
2004-11-19 09:53:51 +00:00
|
|
|
print "New attack", newattacks, ":", claim, " using",CommandLine( protocols)
|
2004-11-18 16:14:31 +00:00
|
|
|
#
|
|
|
|
# TODO
|
|
|
|
#
|
|
|
|
# Generate output to recreate/draw the
|
|
|
|
# attack, and maybe add this to a big
|
|
|
|
# error log thingy. Furthermore,
|
|
|
|
# explicitly recreate the commandline
|
|
|
|
# and the claim that is newly violated
|
2004-11-19 09:53:51 +00:00
|
|
|
DescribeContext (sys.stdout, protocols, claim)
|
2004-11-18 15:06:41 +00:00
|
|
|
|
|
|
|
# Next!
|
|
|
|
processed = processed + 1
|
|
|
|
|
2004-11-18 15:50:54 +00:00
|
|
|
ClearProgress (TupleCount, safetxt)
|
2004-11-18 15:06:41 +00:00
|
|
|
print "Processed", processed,"tuple combinations in total."
|
2004-11-18 16:07:58 +00:00
|
|
|
print "Found", newattacks, "new attacks."
|
2004-11-18 15:06:41 +00:00
|
|
|
|
|
|
|
inp.close()
|