#!/usr/bin/python """ Example script to show how to perform large-scale tests using the Scyther Python API (contained in the Scyther subdirectory) In this example, multi-protocol attack analysis is performed on a small test set. """ import Scyther.Scyther as Scyther def MyScyther(protocollist,filter=None): """ Evaluate the composition of the protocols in protocollist. If there is a filter, i.e. "ns3,I1" then only this specific claim will be evaluated. """ s = Scyther.Scyther() s.options = "--match=2" if filter: s.options += " --filter=%s" % (filter) for protocol in protocollist: s.addFile(protocol) s.verify() return s def getCorrectIsolatedClaims(protocolset): """ Given a set of protocols, determine the correct claims when run in isolation. Returns a tuple, consisting of - a list of compiling protocols - a list of tuples (protocol,claimid) wich denote correct claims """ correctclaims = [] goodprotocols = [] for protocol in protocolset: # verify protocol in isolation s = MyScyther([protocol]) # investigate the results if not s.errors: goodprotocols.append(protocol) for claim in s.claims: if claim.okay: correctclaims.append((protocol,claim.id)) return (goodprotocols,correctclaims) def verifyMPAlist(mpalist,claimid): """ Verify the existence of an attack in this context If an attack is found, we return False, otherwise True. This is needed for the iteration later. """ # This should be a more restricted verification s = MyScyther(mpalist,claimid) claim = s.getClaim(claimid) if claim: if not claim.okay: # This is an MPA attack! print "I've found a multi-protocol attack on claim %s in the context %s." % (claimid,str(mpalist)) return False else: return True def constructMPAlist(protocolset,claimid,mpalist,length,start,callback): """ Append a list of parallel protocols, without duplicates, such that the added part is lexicographically ordered (from index 'start' in the protocol list) For each possible list, the function callback is called. If the callback returns true, iteration proceeds (returning true in the end), otherwise it aborts and returns false. """ if len(mpalist) < length: # list is not long enough yet for pn in range(start,len(protocolset)): p = protocolset[pn] if p not in mpalist: if not constructMPAlist(protocolset,claimid,mpalist + [p],length,pn+1,callback): return False return True else: # list is long enough: callback return callback(mpalist,claimid) def findMPA(protocolset,protocol,claimid,maxcount=3): """ The protocol claim is assumed to be correct. When does it break? """ # First we examine 2-protocol attacks, and then increase the # number of parallel protocols if we don't find any attacks on the # claim. count = 2 if len(protocolset) < maxcount: # we cannot have more protocols in parallel than there are # protocols. maxcount = len(protocolset) # the actual incremental search loop while count <= maxcount: constructMPAlist(protocolset,claimid,[protocol],count,0,verifyMPAlist) count += 1 return None def findAllMPA(protocolset,maxcount=3): """ Given a set of protocols, find multi-protocol attacks """ # Find all correct claims in each protocol (protocolset,correct) = getCorrectIsolatedClaims(protocolset) # For all these claims... for (protocol,claimid) in correct: # Try to find multi-protocol attacks findMPA(protocolset,protocol,claimid,maxcount=3) if __name__ == '__main__': """ Simple test case with a few protocols """ list = ['nsl3-broken.spdl','ns3.spdl','nsl3.spdl'] print "Performing multi-protocol analysis for the following protocols:", list print findAllMPA(list) print print "Analysis complete."