scyther/scripts/if2spdl/parser.py

261 lines
8.3 KiB
Python
Raw Normal View History

2005-11-16 16:24:18 +00:00
#!/usr/bin/python
# requires python-pyparsing module
# http://pyparsing.sourceforge.net/
2005-11-28 14:31:16 +00:00
from pyparsing import Literal, alphas, nums, Word, oneOf, Or, Group, \
2005-11-29 14:16:36 +00:00
restOfLine, Forward, Optional, delimitedList, alphanums,\
OneOrMore
2005-11-16 19:07:19 +00:00
import Term
2005-11-16 16:24:18 +00:00
2005-11-28 14:31:16 +00:00
typedversion = False
2005-11-29 14:16:36 +00:00
# Markers:
#
# TODO stuff that still needs to be done.
# DEVIANT stuff that deviates from the original BNF specs in the
# paper.
# TEST test things, remove later
# Generate parser
2005-11-28 14:31:16 +00:00
#
# Takes a list of tokens, returns
2005-11-29 14:16:36 +00:00
def ruleParser ():
2005-11-28 14:31:16 +00:00
global typedversion
# ------------------------------------------------------
# Atomic
# ------------------------------------------------------
# Tokens
lbr = Literal("(").suppress()
rbr = Literal(")").suppress()
comma = Literal(",").suppress()
hash = Literal("#").suppress()
equ = Literal("=").suppress()
implies = Literal("=>").suppress()
dot = Literal(".").suppress()
eol = Literal("\n").suppress()
# Basic constructors
Alfabet= alphas+nums+"_$"
Number = Word(nums)
Number.setParseAction(lambda s,l,t: [ "number", Term.TermConstant(t[0]) ])
# Typeinfo/Constant
TypeInfo = oneOf ("mr nonce pk sk fu table")
TypeInfo.setParseAction(lambda s,l,t: [ "typeinfo", Term.TermConstant(t[0]) ])
2005-11-29 14:16:36 +00:00
Constant = Word(alphas,Alfabet)
Constant.setParseAction(lambda s,l,t: [ "constant", Term.TermConstant(t[0]) ])
2005-11-28 14:31:16 +00:00
# Time
nTime = Group(Number)
nTime.setParseAction(lambda s,l,t: ["n", t[0] ])
xTime = Literal("xTime")
2005-11-29 14:16:36 +00:00
xTime.setParseAction(lambda s,l,t: ["x", t[0] ])
2005-11-28 14:31:16 +00:00
sTime = Literal("s").suppress() + lbr + Group(Number) + rbr
sTime.setParseAction(lambda s,l,t: ["s", t[0] ])
Time = Or([nTime,xTime,sTime])
Time.setParseAction(lambda s,l,t: ["time", t[0],t[1] ])
2005-11-29 14:16:36 +00:00
# Const
Const = Forward()
Const << Or ([ Constant, Literal("c") + lbr + Constant + comma + Time + rbr, Literal("c(ni,ni)") ])
2005-11-28 14:31:16 +00:00
# Two versions
Variable = Word("x",Alfabet)
Variable.setParseAction(lambda s,l,t: [ "v", Term.TermVariable(t[0],None) ])
if typedversion:
2005-11-29 14:16:36 +00:00
Variable = TypeInfo + lbr + Variable + rbr
# Optional prime
optprime = Optional(Literal("'"))
2005-11-28 14:31:16 +00:00
# Atomic
2005-11-29 14:16:36 +00:00
## DEVIANT : below there is an optprime after the atom. This
## is not in the BNF.
Atomic = Or([ TypeInfo + lbr + Const + rbr, Variable]) + optprime
2005-11-28 14:31:16 +00:00
### TEST
2005-11-29 14:16:36 +00:00
#print Time.parseString("s(25)")
#print Variable.parseString("xCas")
#print Atomic.parseString("nonce(Koen)")
2005-11-28 14:31:16 +00:00
# ------------------------------------------------------
# Messages
# ------------------------------------------------------
# Base forward declaration
Message = Forward()
# Agents etc
Agent = Or ([Literal("mr") + lbr + Const + rbr, Variable])
KeyTable = Or ([Literal("table") + lbr + Const + rbr, Variable])
KeyTableApp = Literal("tb") + lbr + KeyTable + comma + Agent + rbr + optprime
# Crypto
pkterm = Literal("pk") + lbr + Const + rbr + optprime
varterm = Variable + optprime
Invertible = Or( [pkterm, KeyTableApp, varterm])
PublicCypher = Literal("crypt") + lbr + Invertible + comma + Message + rbr
XOR = Literal("rcrypt") + lbr + Message + comma + Message + rbr
SymmetricCypher = Literal("scrypt") + lbr + Message + comma + Message + rbr
futerm = Or([ Literal("fu") + lbr + Const + rbr, Variable ])
Function = Literal("funct") + lbr + futerm + comma + Message + rbr
# Message composition
Concatenation = Literal("c") + lbr + Message + comma + Message + rbr
Composed = Or([ Concatenation, SymmetricCypher, XOR,
PublicCypher, Function, KeyTable, KeyTableApp ])
2005-11-29 14:16:36 +00:00
Message << Or ([Composed, Atomic])
### TEST
#print Message.parseString("nonce(c(Na,xTime))")
2005-11-28 14:31:16 +00:00
# ------------------------------------------------------
# Model of honest agents
# ------------------------------------------------------
Boolean = Or ([ Literal("true"), Literal("false"), Variable ])
Session = Forward()
2005-11-29 14:16:36 +00:00
Session << Or ([ Literal("s") + lbr + Session + rbr, Number, Variable ])
2005-11-28 14:31:16 +00:00
MsgEtc = Literal("etc")
2005-11-29 14:16:36 +00:00
MsgList = Forward()
2005-11-28 14:31:16 +00:00
MsgComp = Literal("c") + lbr + Message + comma + MsgList + rbr
2005-11-29 14:16:36 +00:00
MsgList << Or ([ MsgEtc, Variable, MsgComp ])
2005-11-28 14:31:16 +00:00
Step = Or ([ Number, Variable ])
### TEST
2005-11-29 14:16:36 +00:00
#print Message.parseString("xKb")
#print MsgList.parseString("etc")
#print MsgList.parseString("c(xKb,etc)")
#print MsgList.parseString("c(xA,c(xB,c(xKa,c(xKa',c(xKb,etc)))))")
2005-11-28 14:31:16 +00:00
# Principal fact
Principal = Literal("w") + lbr + Step + comma + Agent + comma + Agent + comma + MsgList + comma + MsgList + comma + Boolean + comma + Session + rbr
# Message fact
MessageFact = Literal("m") + lbr + Step + comma + Agent + comma + Agent + comma + Agent + comma + Message + comma + Session + rbr
# Goal fact
2005-11-29 14:16:36 +00:00
Correspondence = Principal + dot + Principal
Secret = Literal("secret") + lbr + Message + Literal("f") + lbr + Session + rbr + rbr
Secrecy = Literal("secret") + lbr + Literal("xsecret") + comma + Literal("f") + lbr + Session + rbr + rbr + dot + Literal("i") + lbr + Literal("xsecret") + rbr
Give = Literal("give") + lbr + Message + Literal("f") + lbr + Session + rbr + rbr
STSecrecy = Literal("give(xsecret,f(xc)).secret(xsecret,f(xc))") + implies + Literal("i(xsecret)")
Witness = Literal("witness") + lbr + Agent + comma + Agent + comma + Constant + comma + Message + rbr
Request = Literal("request") + lbr + Agent + comma + Agent + comma + Constant + comma + Message + rbr
Authenticate = Literal("request") + lbr + Agent + comma + Agent + comma + Constant + comma + Message + rbr
GoalState = Or ([ Correspondence, Secrecy, STSecrecy, Authenticate ])
GoalFact = Or ([ Secret, Give, Witness, Request ])
2005-11-28 14:31:16 +00:00
# TimeFact
TimeFact = Literal("h") + lbr + Message + rbr
# Intruder knowledge
IntruderKnowledge = Literal("i") + lbr + Message + rbr
2005-11-28 14:31:16 +00:00
# Facts and states
Fact = Or ([ Principal, MessageFact, IntruderKnowledge, TimeFact, Secret, Give, Witness, Request ])
2005-11-29 14:16:36 +00:00
State = Group(delimitedList (Fact, ".")) ## From initial part of document, not in detailed BNF
2005-11-28 14:31:16 +00:00
# Rules
2005-11-29 14:16:36 +00:00
MFPrincipal = Or ([ MessageFact + dot + Principal, Principal ])
mr1 = Literal("h") + lbr + Literal("s") + lbr + Literal("xTime") + rbr + rbr + dot + MFPrincipal
2005-11-28 14:31:16 +00:00
mr2 = implies
2005-11-29 14:16:36 +00:00
mr3 = Literal("h") + lbr + Literal("xTime") + rbr + dot + MFPrincipal + Optional(dot + delimitedList(GoalFact, "."))
MessageRule = mr1 + mr2 + mr3 ## DEVIANT : BNF requires newlines
InitialState = Literal("h") + lbr + Literal("xTime") + rbr + dot + State ## DEVIANT : BNF requires newlines
2005-11-28 14:31:16 +00:00
# Intruder
IntruderRule = Literal("nogniet")
# Simplification
2005-11-29 14:16:36 +00:00
f_simplif = Literal("f") + lbr + Literal("s") + lbr + Literal ("xc") + rbr + rbr + implies + Literal("f") + lbr + Literal("xc") + rbr ## DEVIANT : EOL removed
matching_request = Witness + dot + Request + implies
no_auth_intruder = Request + implies
SimplificationRule = Or ([ f_simplif, matching_request, no_auth_intruder ])
2005-11-28 14:31:16 +00:00
# Compose all rules
Rule = Or([ InitialState, MessageRule, IntruderRule, GoalState, SimplificationRule ])
2005-11-29 14:16:36 +00:00
return Rule
2005-11-28 14:31:16 +00:00
2005-11-29 14:16:36 +00:00
# IFParser
# Does not work for the first line (typed/untyped)
# Depends on ruleParser
def ifParser():
2005-11-28 14:31:16 +00:00
comma = Literal(",").suppress()
hash = Literal("#").suppress()
2005-11-29 14:16:36 +00:00
equal = Literal("=").suppress()
2005-11-16 16:24:18 +00:00
# Rules and labels
rulename = Word (alphanums + "_")
rulecategory = oneOf("Protocol_Rules Invariant_Rules Decomposition_Rules Intruder_Rules Init Goal")
2005-11-29 14:16:36 +00:00
label = hash + Literal("lb") + equal + rulename + comma + Literal("type") + equal + rulecategory
labeledrule = Group(label) + Group(ruleParser())
def labeledruleAction(s,l,t):
print "-----------------"
print "- Detected rule -"
print "-----------------"
print t[0]
print t[1]
print
labeledrule.setParseAction(labeledruleAction)
2005-11-16 16:24:18 +00:00
# A complete file
parser = OneOrMore(labeledrule)
2005-11-16 16:24:18 +00:00
parser.ignore("##" + restOfLine)
2005-11-29 14:16:36 +00:00
return parser
# Determine (un)typedness from this line
def typeSwitch(line):
try:
global typedversion
typeflag = Literal("#") + "option" + Literal("=") + oneOf ("untyped","typed")
res = typeflag.parseString(line)
if res[3] == "untyped":
typedversion = False
elif res[3] == "typed":
typeversion = True
else:
print "Cannot determine whether typed or untyped."
raise ParseException
except:
print "Unexpected error while determining (un)typedness of the line", line
2005-11-16 16:24:18 +00:00
str = "Detected "
if not typedversion:
str += "un"
str += "typed version."
print str
2005-11-29 14:16:36 +00:00
# Parse an entire file, including the first one
def linesParse(lines):
typeSwitch(lines[0])
parser = ifParser()
result = parser.parseString("".join( lines[1:]))
# Main code
2005-11-28 14:31:16 +00:00
def main():
2005-11-29 14:16:36 +00:00
file = open("NSPK_LOWE.if", "r")
linesParse(file.readlines())
file.close()
2005-11-28 14:31:16 +00:00
if __name__ == '__main__':
main()
2005-11-16 16:24:18 +00:00