mirror of
https://github.com/NationalSecurityAgency/maat.git
synced 2026-11-08 08:12:02 -10:00
475 lines
17 KiB
Python
475 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 ('Attestation Service Providers (ASPs)')
|
|
print ('_____________________________________________________\n')
|
|
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 printASPTableHeader():
|
|
nc = 20
|
|
dc = 70
|
|
ic = 70
|
|
oc = 70
|
|
nameColumn = "=" * nc;
|
|
descColumn = "=" * dc;
|
|
inputColumn = "=" * ic;
|
|
outputColumn = "=" * oc;
|
|
|
|
# print('.. tabularcolumns:: |p{6.35cm}|p{6.35cm}|p{6.35cm}|\n');
|
|
|
|
print('.. table:: ' + "ASPs " + "\n" +
|
|
'\t:widths: 20, 70, 70\n' +
|
|
'\t:column-alignment: left left left \n' +
|
|
'\t:column-wrapping: true true true\n' +
|
|
'\t:column-dividers: single single single single\n' +
|
|
'\n' +
|
|
'\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + "\n" +
|
|
'\tType' + (" " * (nc-4)) + ' ' + 'Name' + (" " * (dc -4)) + ' Description \n' +
|
|
'\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn)
|
|
|
|
|
|
|
|
#print('\n' +
|
|
# ' \t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + "\n" +
|
|
# ' \tName' + (" " * (nc-4)) + ' ' + 'Description' + (" " * (dc -11)) + ' Type \n' +
|
|
# ' \t' + nameColumn + ' ' + descColumn + ' ' + inputColumn)
|
|
|
|
|
|
return
|
|
|
|
def printASPTableFooter():
|
|
nc = 20
|
|
dc = 70
|
|
ic = 70
|
|
oc = 70
|
|
nameColumn = "=" * nc;
|
|
descColumn = "=" * dc;
|
|
inputColumn = "=" * ic;
|
|
outputColumn = "=" * oc;
|
|
|
|
print(' \t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + "\n");
|
|
|
|
return
|
|
|
|
|
|
def printASPsTable(title, asps):
|
|
"Print Table of list of asps provided with Name, Description, Input and Ouptut as Columns"
|
|
nc = 20
|
|
dc = 70
|
|
ic = 70
|
|
oc = 70
|
|
nameColumn = "=" * nc;
|
|
descColumn = "=" * dc;
|
|
inputColumn = "=" * ic;
|
|
outputColumn = "=" * oc;
|
|
|
|
# print('.. table:: ' + title + "\n" +
|
|
# '\t:widths: 1 1 1\n' +
|
|
# '\t:column-alignment: left left left \n' +
|
|
# '\t:column-wrapping: true true true\n' +
|
|
# '\t:column-dividers: single single single single\n' +
|
|
# '\n' +
|
|
# '\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + "\n" +
|
|
# '\tName' + (" " * (nc-4)) + ' ' + 'Description' + (" " * (dc -11)) + ' Type \n' +
|
|
# '\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn)
|
|
|
|
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 = " " * ic # 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)
|
|
btype = " " * nc
|
|
atype = asp.aspType + btype[len(asp.aspType):] + " "
|
|
if (meas != ""):
|
|
tmp = "measurement: " + meas
|
|
else:
|
|
tmp = ''
|
|
out = tmp + out[len(tmp):]
|
|
row1 = "\t"+ atype + name + desc
|
|
|
|
# build row 2
|
|
name = " " * ic # 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 = ' '
|
|
atype = " " * nc
|
|
row2 = "\t" + atype + " " + name + desc
|
|
|
|
# build row 3
|
|
name = " " * ic # 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 = " "
|
|
atype = " " * nc
|
|
row3 = "\t" + atype + " " + name + desc
|
|
|
|
# build row 4
|
|
name = " " * ic # 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 = " "
|
|
atype = " " * nc
|
|
row4 = "\t" + atype + " " + name + desc
|
|
|
|
print(" " + row1);
|
|
print(" " + row2);
|
|
print(" " + row3);
|
|
print(" " + row4);
|
|
|
|
# print('\t' + nameColumn + ' ' + descColumn + ' ' + inputColumn + "\n");
|
|
|
|
return
|
|
|
|
def printASPInfo(asp):
|
|
"Print XML Info"
|
|
print('.. rst-class:: html-toggle');
|
|
|
|
print ('.. _' + asp.uuid + ':\n\n' + 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(asp.detaileddesc);
|
|
|
|
print("Usage: ");
|
|
print(asp.usage);
|
|
print("Description: \n");
|
|
print("\t" + asp.desc + "\n");
|
|
print("Input Description: " );
|
|
print(asp.inpdesc);
|
|
print("Output Description: ");
|
|
print(asp.outdesc);
|
|
if (asp.example != ''):
|
|
print("Example:: ");
|
|
print(asp.example);
|
|
print(".. seealso::");
|
|
print(asp.seealso);
|
|
|
|
print('| Filename: ' + asp.filename + '.c')
|
|
print('| UUID: ' + asp.uuid)
|
|
print('| Description: \n| \t' + asp.desc)
|
|
print('| Measurers: ')
|
|
for name in asp.measurers:
|
|
print('| \t' + name)
|
|
if (asp.measurersdesc != ''):
|
|
print("| \t\tNote: " + asp.measurersdesc);
|
|
print('| \tCapabilities:');
|
|
if (asp.targetmagic != ''):
|
|
print("| \t\tTarget Type: " + makeUrlLink(asp.targettype, asp.targetmagic));
|
|
if (asp.targetdesc != ''):
|
|
print("| \t\t\t\tDescription: " + asp.targetdesc)
|
|
if (asp.addrmagic != '' ):
|
|
print("| \t\tAddress Type: " + makeUrlLink(asp.addrtype, asp.addrmagic));
|
|
if (asp.addrdesc != ''):
|
|
print("| \t\t\t\tDescription: " + asp.addrdesc)
|
|
if (asp.measmagic != ''):
|
|
print("| \t\tMeasurement Type: " + makeUrlLink(asp.meastype, asp.measmagic));
|
|
if (asp.measdesc != ''):
|
|
print("| \t\t\t\tDescription: " + asp.measdesc)
|
|
if (asp.feature != ''):
|
|
print("| \t\t\t\tFeature: " + asp.feature)
|
|
|
|
print("| Security: ")
|
|
print('| \tType: ' + asp.selinuxtype)
|
|
print('| \tUser: ' + asp.user)
|
|
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("Parse ASP Error for: " + filepath)
|
|
error_msg = ErrorString(expatError.code)
|
|
error_msg += ' at line ' + str(expatError.lineno) + ' column ' + str(expatError.offset)
|
|
print(error_msg);
|
|
return None
|
|
except AttributeError as ae:
|
|
print(ae)
|
|
return None
|
|
except:
|
|
print("Parse ASP: " + filepath + " 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(ae)
|
|
return None
|
|
except:
|
|
print("Unexpected error: " + sys.exc_info()[0])
|
|
return None
|
|
|
|
return parsedasp
|
|
|
|
# Print SPHYNX Header
|
|
printHeader()
|
|
|
|
# Parse and Organize ASPs
|
|
for root, directories, files in os.walk(ASPsLocation):
|
|
for filename in sorted(files):
|
|
if filename.endswith(".xml"):
|
|
#print("Parsing File :" + filename + "\n");
|
|
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
|
|
|
|
printASPTableHeader();
|
|
|
|
printASPsTable("Appraisal ASPs", appraisalAsps);
|
|
printASPsTable("File ASPs", fileAsps);
|
|
printASPsTable("Kernel ASPs", kernelAsps);
|
|
printASPsTable("Network ASPs", networkAsps);
|
|
printASPsTable("Process ASPs", processAsps);
|
|
printASPsTable("System ASPs", systemAsps);
|
|
|
|
printASPTableFooter();
|