Greetings, colleagues!

In the process of researching the
OVAL language, about which I wrote earlier in one of my
articles , and the concept of a
SCAP scanner, I faced a rather serious problem, namely the lack of convenient tools for creating content in the
OVAL language
. No, I do not claim that there is nothing at all. There is a small set of
utilities presented on the official site. Most of them are paid, the rest are not very convenient solutions, most of all similar to
XML-Notepad . In the end, I decided to create the
small tool I needed to work on my own, using Python as the language.
Such a choice is due to the good reputation of the Python language as
“rapid development language” and the presence of a rich palette of third-party libraries. Armed with language documentation, I tried to recreate
MITER’s ideas in reality. The final goal for me was to set up the implementation of OVAL objects and their storage and indexing systems.
')
The primary issue was the choice of method of storing the collected information. The first (and unsuccessful) solution was
SQLite 3 . I will not particularly linger on this sad experience, but experience has shown that storing an unpredictable tree in a relational database is too difficult for me. Therefore, I drew attention to the
NoSQL database . Since I was planning to restrict myself to the exclusive use of the base, my choice fell on
ZoDB . Of course, this decision was also hasty. But it was too late to rework on
MongoDB . So for further code calculations, I would like to note that
PersistentMapping () is, in fact, the usual
dict () . Taking into account the uncertainty of the perception of the hashmaps database, as a hashmap, I used the keys of the same class.
PersistentList () is the equivalent of
list () . This replacement is necessary for storing such structures in ZoDB. This is due to the internal logic of the database. To save a class in the database, it is entirely necessary that the class be the heir of the
persistent.Persistent class.
In addition, I ask you in advance to forgive me for the non-template naming of variables, methods and classes and the possible "kosawkost": I am not a wizard, I am just learning. And I will gladly accept any edits and comments from more knowledgeable colleagues.
In order to avoid quoting unnecessarily large pieces of code, I immediately cite a link to the
source code on code.google.com .
In general, when analyzing the structures of the OVAL language, I noted that its main feature is extensibility. If you need to enter your own structure, it is enough to describe it in the XSD, which defines your namespace. Since the structures for the most part represent typical data sets, I decided to create a dedicated class for each language object. The main goal of such an implementation is to create a container for information that will be conveniently stored in the database. Thus, the
OBJECT element was used as the base object:
# UNIVERSAL OVAL OBJECTS
class oval_object ( persistent. Persistent ) :
def __init__ ( self ) :
self . id = str ( )
self . tag = "object"
self . namespace = str ( )
self . oval = str ( )
self . version = 0
self . vHash = 0
self . deprecated = False
self . variables = PersistentList ( )
self . notes = PersistentList ( )
self . comment = str ( )
self . signature = str ( )
def assign_id ( self , UniqId ) :
self . id = "oval:" + self . oval + ": obj:" + str ( UniqId )
def hash ( self ) :
summ_hash = 0
summ_hash + = hash ( self . tag )
summ_hash + = hash ( self . namespace )
summ_hash + = hash ( self . comment )
for var in self . variables :
if isinstance ( var, variable ) :
summ_hash + = var. hashme ( )
else :
raise Exception ( "Error input parameters in object variables" )
return summ_hash
def hashme ( self ) :
self . vHash = self . hash ( )
return self . vHash
def clearme ( self ) :
hashmap = PersistentMapping ( )
for var in self . variables :
var. clearme ( )
var_hash = var. hashme ( )
if var_hash not in hashmap. keys ( ) :
hashmap [ var_hash ] = None
else :
self . variables . remove ( var )
This class is the base class for all major
OVAL elements.
Definition ,
Test ,
State and
Oval_variable will be the heirs of this class. In order to realize the possibility of comparing elements, the methods
hash () (universal for all) and
hashme () (redefined by descendants) were created.
As can be seen from the names of the variables, all the basic structures are given statically. Dynamic are the possible "descendants", the structures of which we do not know. To implement such "descendants", I made the class
Variable , largely repeating according to the
Element ideology from the
ElementTree :
class variable ( persistent. Persistent ) :
def __init__ ( self , tag = str ( ) , body = str ( ) , attributes = None , variables = None ) :
if not attributes:
self . attributes = PersistentMapping ( )
if not variables:
self . variables = PersistentList ( )
if attributes and not isinstance ( attributes, PersistentMapping ) :
attributes = PersistentMapping ( attributes )
if variables and not isinstance ( variables, PersistentList ) :
variables = PersistentList ( variables )
self . tag = tag
self . body = body
if attributes:
self . attributes = attributes
if variables:
self . variables = variables
self . vHash = 0
def clearme ( self ) :
hashmap = PersistentMapping ( )
for var in self . variables :
var. clearme ( )
var_hash = var. hashme ( )
if var_hash not in hashmap. keys ( ) :
hashmap [ var_hash ] = None
else :
self . variables . remove ( var )
def hashme ( self ) :
summ_hash = 0
summ_hash + = hash ( self . tag )
summ_hash + = hash ( self . body )
if self . attributes :
for attribute in self . attributes . keys ( ) :
summ_hash + = hash ( attribute ) + hash ( self . attributes [ attribute ] )
if self . variables :
for var in self . variables :
if isinstance ( var, variable ) :
if var ! = self :
summ_hash + = var. hashme ( )
else :
raise Exception ( "Error input parameters in variables. Self append?" )
self . vHash = summ_hash
return self . vHash
As with
OBJECT , the hash calculation function was required. The class structure is maximally tailored to
ElementTree.Element to simplify the future uploading of the database to the XML format.
In general, a set of objects that are convenient to fill out. But it is not enough to fill them: when creating your own objects, it is necessary to fulfill the requirements of the regulator (in our case
MITRE ) for filling and storing new
Definition . Accordingly, I needed an indexing and change control system for the Definition version. For this, the
oval_suite () class was created. It implements a basic set of methods (
put ,
get ,
delete ,
search ,
import_xml ,
export_xml ), which facilitates work with content and allows you not to bother with the aforementioned problems.
One of the specific problems I encountered in the process of creating
oval_suite () is the lack of memory when trying to export a large amount of data (about 100MB) to XML format in one go. Therefore, to implement this function, we had to create the final file in stages and use the
ElementTree.Element function for deleting elements, borrowed from
StackOverflow :
def _garbager ( self , root ) :
for element in list ( root ) :
self ._garbager ( element )
root clear ( )
del root
In general and in general, we have sketched tools for working with
OVAL in Python, which can be useful in building and creating security content. This module allows you to build security content and “package” it into a database with version control and unique identifiers.
Thanks for attention! I hope someone will be interested in the topic of
OVAL and these developments will be useful to him.