Files

462 lines
17 KiB
Python

#
# Copyright 2023 United States Government
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
import sys
from xml.dom import minidom
from xml.parsers.expat import ExpatError, ErrorString
class asp(object):
def __init__(self):
self.name = 'none'
self.uuid = ''
self.aspType = ''
self.desc = ''
self.detaileddesc = ''
self.inpdesc = ''
self.outdesc = ''
self.usage = ''
self.aspfile = ''
self.measurers = []
self.measurersdesc = ''
self.targettype = ''
self.targetmagic = ''
self.targetdesc = ''
self.addrtype = ''
self.addrmagic = ''
self.addrdesc = ''
self.meastype = ''
self.measmagic =''
self.measdesc = ''
self.feature = ''
self.filename = ''
self.selinuxtype = ''
self.seealso = ''
self.example = ''
self.user = ''
# Variables
ASPsLocation = sys.argv[1]
allAsps = []
demoAsps = []
networkAsps = []
fileAsps = []
processAsps = []
systemAsps = []
appraisalAsps = []
kernelAsps = []
def printHeader( ):
"This Function Prints SPHINX Header to Standard Output"
print ('=============================================')
print ('Attestation Service Providers (ASPs)')
print ('=============================================')
print ('')
print ('.. currentmodule:: maat\n')
print ('Attestation Service Providers (ASPs) are the basic func' +
'tional unit of Maat. Each ASP performs a specific, discrete' +
' function in evidence collection tasks. An ASP may be a' +
' measurement agent responsible for gathering a specific piece' +
' of evidence from the system. An ASP may also be a evaluation' +
' unit that ingests some type of evidence and contributes to an' +
' assessment of the target\'s integrity. Other ASPs may provide' +
' post-processing functions such as hashing or compression, or' +
' call out to external components such as another AM or an' +
' existing service.\n')
return
def makeASPLink(name, uuid):
"Helper Function to create url link giving name and magic number"
if (name == ""):
return "";
return """:ref:`""" + name + """ <""" + uuid + """>`"""
def makeUrlLink(name, magic):
"Helper Function to create url link giving name and magic number"
if (name == ""):
return "";
return """:ref:`""" + name + """ <Magic""" + magic + """>`"""
def printASPsTable(title, asps):
"Print Table of list of asps provided with Name, Description, Input and Ouptut as Columns"
nc = 70
dc = 50
ic = 70
oc = 70
nameColumn = "=" * nc;
descColumn = "=" * dc;
inputColumn = "=" * ic;
outputColumn = "=" * oc;
print('.. table:: ' + title + "\n" +
'\t:widths: 1 1 1 1\n' +
'\t:column-alignment: left left left left\n' +
'\t:column-wrapping: true true true true\n' +
'\t:column-dividers: single single single single single\n' +
'\n' +
'\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + ' ' + outputColumn + "\n" +
'\tName' + (" " * (nc-4)) + ' ' + 'Description' + (" " * (dc -11)) + ' ' + 'Input' + (" " * (ic-5)) + ' ' + 'Output \n' +
'\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + ' ' + outputColumn)
for asp in asps:
# Build Table contents
# ASP has up to 4 rows
# Row 1 -> ASP Name, Desc(0.50), graph{, graph{
# Row 2 -> ,Desc(50,100), address_space, measurement_type
# Row 3 -> ,Desc(100,101), target_type, }
# Row 4 -> ,Desc(101,150), } nodeid,
# Sphynx may combine some of these fields to reduce rows
# build row 1
name = " " * nc # Pad name field, so table lines up
asplink = makeASPLink(asp.name, asp.uuid)
name = asplink + name[len(asplink):] + " "
desc = " " * dc # Pad desc field, so table lines up
adesc = asp.desc[0:dc].lstrip()
adesc = adesc.replace("\n","");
adesc = adesc.replace("\t", "");
desc = adesc + desc[len(adesc):] + " "
inp = " " * ic
addr = makeUrlLink(asp.addrtype, asp.addrmagic)
tmp = "graph {" + addr
inp = tmp + inp[len(tmp):] + " "
out = " " * oc
meas = makeUrlLink(asp.meastype, asp.measmagic)
if (meas != ""):
tmp = "measurement: " + meas
else:
tmp = ''
out = tmp + out[len(tmp):]
row1 = "\t" + name + desc + inp + out
# build row 2
name = " " * nc # No Name in Row 2
name = name + " "
desc = " " * dc # Pad desc field, so table lines up
adesc = asp.desc[dc:dc*2].lstrip()
adesc = adesc.replace("\n","");
adesc = adesc.replace("\t", "");
desc = adesc + desc[len(adesc):] + " "
inp = " " * ic
target = makeUrlLink(asp.targettype, asp.targetmagic)
tmp = ", " + target + "}, nodeid"
inp = tmp + inp[len(tmp):]
if (meas != ""):
out = " added to input node "
else:
out = ' '
row2 = "\t" + name + desc + inp + out
# build row 3
name = " " * nc # No Name in Row 3
name = name + " "
desc = " " * dc # Pad desc field, so table lines up
adesc = asp.desc[2*dc:3*dc].lstrip()
adesc = adesc.replace("\n","");
adesc = adesc.replace("\t","");
desc = adesc + desc[len(adesc):] + " "
inp = " "
out = " "
row3 = "\t" + name + desc + inp + out
# build row 4
name = " " * nc # No Name in Row 4
name = name + " "
desc = " " * dc # Pad desc field, so table lines up
adesc = asp.desc[3*dc:4*dc].lstrip()
adesc = adesc.replace("\t", "");
adesc = adesc.replace("\n","");
desc = adesc + desc[len(adesc):] + " "
inp = " "
out = " "
row4 = "\t" + name + desc + inp + out
print(row1);
print(row2);
print(row3);
print(row4);
print('\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + ' ' + outputColumn + "\n");
return
def printASPInfo(asp):
"Print XML Info"
print('.. rst-class:: html-toggle');
print ('')
print ('.. _' + asp.uuid + ':')
print ('')
#print ('========================================================')
print (asp.name)
print ('---------------------------------------------------------')
if (asp.targettype != ''):
asp.detaileddesc = asp.detaileddesc.replace(asp.targettype, """:ref:`""" + asp.targettype + """ <""" + "Magic" + asp.targetmagic + """>`""")
if (asp.addrtype != ''):
asp.detaileddesc = asp.detaileddesc.replace(asp.addrtype, """:ref:`""" + asp.addrtype + """ <""" + "Magic" + asp.addrmagic + """>`""")
if (asp.meastype != ''):
asp.detaileddesc = asp.detaileddesc.replace(asp.meastype, """:ref:`""" + asp.meastype + """ <""" + "Magic" + asp.measmagic + """>`""")
print("\nUsage: ");
print(asp.usage);
print("\nDescription: \n");
print("\t" + asp.desc + "\n");
print("\nInput Description: " );
print(asp.inpdesc);
print("\nOutput Description: ");
print(asp.outdesc);
if (asp.example != ''):
print("\nExample:: ");
print(asp.example);
if (asp.seealso != ''):
print("\n.. seealso::");
print(asp.seealso);
print("\n");
print(".. raw:: latex");
print("");
print(" \clearpage")
print('')
return
def parseASPXml( filepath ):
"Parse ASP XML"
doc = parseXml( filepath );
if (doc is not None):
parsedasp = parseASPFields(doc)
return parsedasp
return None
def getElementData(minidoc, fieldname):
"Get first child data of element matching fieldname (if present)"
fs = minidoc.getElementsByTagName(fieldname)
if (fs.length > 0):
return minidoc.getElementsByTagName(fieldname)[0].firstChild.data
return ""
def parseXml( filepath ):
"minidom xml parsing"
try:
doc = minidom.parse(filepath)
return doc
except IOError as e:
print("I/O error ({0}): {1}".format(e.errno, e.strerror))
return None
except ExpatError as expatError:
print("Minidom Parse Error: " + str(expatError) + " when parsing " + filepath)
return None
except AttributeError as ae:
print("Attribute error " + str(ae) + " when parsing file " + filepath)
print(ae)
return None
except:
print("Error parsing file: " + filepath)
print("Unexpected error: " + sys.exc_info()[0])
return None
def parseASPFields(doc):
"Parse ASP Fields from minidom xml object"
parsedasp = asp();
try:
# ASP meta data
parsedasp.name = getElementData(doc, "name")
parsedasp.uuid = getElementData(doc, "uuid")
parsedasp.aspType = getElementData(doc, "type")
parsedasp.filename = getElementData(doc, "aspfile")
# ASP documentation
parsedasp.detaileddesc = getElementData(doc, "detaileddescription")
parsedasp.desc = getElementData(doc, "description")
parsedasp.example = getElementData(doc, "example")
parsedasp.usage = getElementData(doc, "usage")
parsedasp.inpdesc = getElementData(doc, "inputdescription")
parsedasp.outdesc = getElementData(doc, "outputdescription")
parsedasp.seealso = getElementData(doc, "seealso").replace(" ", "\n\n\t\t")
measurers = doc.getElementsByTagName("measurers")[0]
satisfiers = measurers.getElementsByTagName("satisfier")
if (satisfiers.length > 0):
satisfier = measurers.getElementsByTagName("satisfier")[0]
measurersdesc = measurers.getElementsByTagName("description")
if (measurersdesc.length > 0):
d = measurers.getElementsByTagName("description")[0]
parsedasp.measurersdesc = d.firstChild.data
measnames = satisfier.getElementsByTagName("value")
for name in measnames:
parsedasp.measurers.append(name.firstChild.data)
capabilities = satisfier.getElementsByTagName("capability")
for capability in capabilities:
if (capability.hasAttribute("target_type")):
parsedasp.targettype = capability.getAttribute("target_type")
if (capability.hasAttribute("target_desc")):
parsedasp.targetdesc = capability.getAttribute("target_desc")
if (capability.hasAttribute("target_magic")):
parsedasp.targetmagic = capability.getAttribute("target_magic")
if (capability.hasAttribute("address_type")):
parsedasp.addrtype = capability.getAttribute("address_type")
if (capability.hasAttribute("address_desc")):
parsedasp.addrdesc = capability.getAttribute("address_desc")
if (capability.hasAttribute("address_magic")):
parsedasp.addrmagic = capability.getAttribute("address_magic")
if (capability.hasAttribute("measurement_type")):
parsedasp.meastype = capability.getAttribute("measurement_type")
if (capability.hasAttribute("measurement_desc")):
parsedasp.measdesc = capability.getAttribute("measurement_desc")
if (capability.hasAttribute("measurement_magic")):
parsedasp.measmagic = capability.getAttribute("measurement_magic")
if (capability.hasAttribute("attribute")):
parsedasp.feature = capability.getAttribute("attribute")
# update links
if (parsedasp.targettype != ''):
parsedasp.inpdesc = parsedasp.inpdesc.replace(parsedasp.targettype, """:ref:`""" + parsedasp.targettype + """ <""" + "Magic" + parsedasp.targetmagic + """>`""")
if (parsedasp.addrtype != ''):
parsedasp.inpdesc = parsedasp.inpdesc.replace(parsedasp.addrtype, """:ref:`""" + parsedasp.addrtype + """ <""" + "Magic" + parsedasp.addrmagic + """>`""")
if (parsedasp.meastype != ''):
parsedasp.outdesc = parsedasp.outdesc.replace(parsedasp.meastype, """:ref:`""" + parsedasp.meastype + """ <""" + "Magic" + parsedasp.measmagic + """>`""")
securitys = doc.getElementsByTagName("security_context")
for security in securitys:
selinux = security.getElementsByTagName("selinux")
if (selinux.length > 0):
selinux = security.getElementsByTagName("selinux")[0]
types = selinux.getElementsByTagName("type")
if (types.length > 0):
field = selinux.getElementsByTagName("type")[0]
parsedasp.selinuxtype = field.firstChild.data
user = security.getElementsByTagName("user")
if (user.length > 0):
field = security.getElementsByTagName("user")[0]
parsedasp.user = field.firstChild.data
return parsedasp
except AttributeError as ae:
print("ASP: " + parsedasp.name + " Attribute Error" + ae)
return None
except:
print("ASP: " + parsedasp.name + " Unexpected error: " + sys.exc_info()[0])
return None
return parsedasp
# Print SPHYNX Header
printHeader()
# Variables
# Parse and Organize ASPs
for root, directories, files in os.walk(ASPsLocation):
for filename in sorted(files):
if filename.endswith(".xml"):
parsedasp = parseASPXml(ASPsLocation + filename);
if parsedasp is None:
break;
allAsps.append(parsedasp)
if parsedasp.aspType == "Appraisal":
appraisalAsps.append(parsedasp)
if parsedasp.aspType == "Demonstration":
demoAsps.append(parsedasp)
if parsedasp.aspType == "Kernel":
kernelAsps.append(parsedasp)
if parsedasp.aspType == "Network":
networkAsps.append(parsedasp)
if parsedasp.aspType == "File":
fileAsps.append(parsedasp)
if parsedasp.aspType == "Process":
processAsps.append(parsedasp)
if parsedasp.aspType == "System":
systemAsps.append(parsedasp)
break; # only top folder, break before recursively checking test folders
# Cloud Plugin - allows for section collapse
print('.. rst-class:: html-toggle');
print('');
#print('*******************************************')
print('Appraisal')
print('============================================')
printASPsTable("Appraisal ASPs", appraisalAsps);
for asp_object in appraisalAsps:
printASPInfo(asp_object)
#printASPsTable("Demonstation ASPs", demoAsps);
#print("Demonstration\n-------------------------------\n")
#for asp_object in demoAsps:
# printASPInfo(asp_object)
# Cloud Plugin - allows for section collapse
print('.. rst-class:: html-toggle');
print('');
#print('*******************************************')
print('File')
print('============================================')
printASPsTable("File ASPs", fileAsps);
for asp_object in fileAsps:
printASPInfo(asp_object)
# Cloud Pluggin - allows for section collapse
print('.. rst-class:: html-toggle');
print('')
#print('*******************************************')
print('Kernel')
print('============================================')
printASPsTable("Kernel ASPs", kernelAsps);
for asp_object in kernelAsps:
printASPInfo(asp_object)
# Cloud Plugin - allows for section collapse
print('.. rst-class:: html-toggle');
print('')
#print('*******************************************')
print('Network')
print('============================================')
printASPsTable("Network ASPs", networkAsps);
for asp_object in networkAsps:
printASPInfo(asp_object)
# Cloud Plugin - allows for section collapse
print('.. rst-class:: html-toggle');
print('')
#print('*******************************************')
print('Process')
print('============================================')
printASPsTable("Process ASPs", processAsps);
for asp_object in processAsps:
printASPInfo(asp_object)
# Cloud Plugin - allows for section collapse
print('.. rst-class:: html-toggle');
print('')
#print('*******************************************')
print('System')
print('============================================')
printASPsTable("System ASPs", systemAsps);
for asp_object in systemAsps:
printASPInfo(asp_object)