Skip to content

Commit

Permalink
Fix RawArtifact attribute settings. Some general improvements. Added …
Browse files Browse the repository at this point in the history
…tests. closes #296
  • Loading branch information
emmanvg committed Nov 22, 2017
1 parent 66ad6d1 commit 296df6e
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 22 deletions.
83 changes: 61 additions & 22 deletions cybox/objects/artifact_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,27 @@ def validate_artifact_type(instance, value):
raise ValueError(err)


def validate_byte_order_endianness(instance, value):
if value is None:
return
elif value in RawArtifact.ENDIANNESS:
return
else:
err = "Type must be one of %s. Received '%s'." % (RawArtifact.ENDIANNESS, value)
raise ValueError(err)


class RawArtifact(String):
_binding_class = artifact_binding.RawArtifactType
_binding = artifact_binding
_binding_class = _binding.RawArtifactType
_namespace = 'http://cybox.mitre.org/objects#ArtifactObject-2'

byte_order = fields.TypedField("byte_order")
BIG_ENDIAN = "Big-endian"
LITTLE_ENDIAN = "Little-endian"
MIDDLE_ENDIAN = "Middle-endian"
ENDIANNESS = (BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN)

byte_order = fields.TypedField("byte_order", postset_hook=validate_byte_order_endianness)


class Packaging(entities.Entity):
Expand All @@ -47,7 +63,8 @@ def unpack(self, packed_data):

class Artifact(ObjectProperties):
# Warning: Do not attempt to get or set Raw_Artifact directly. Use `data`
# or `packed_data` respectively. Raw_Artifact will be set on export.
# or `packed_data` respectively. The Raw_Artifact value will be set on
# export. You can set BaseObjectProperties or PatternFieldGroup attributes.
_binding = artifact_binding
_binding_class = _binding.ArtifactObjectType
_namespace = 'http://cybox.mitre.org/objects#ArtifactObject-2'
Expand All @@ -62,7 +79,8 @@ class Artifact(ObjectProperties):
TYPES = (TYPE_FILE, TYPE_FILE_SYSTEM, TYPE_GENERIC, TYPE_MEMORY, TYPE_NETWORK)

hashes = fields.TypedField("Hashes", HashList)
# packaging = fields.TypedField("Packaging", Packaging, multiple=True) # TODO: Support this as a TypedField
# TODO: Support packaging as a TypedField
# packaging = fields.TypedField("Packaging", Packaging, multiple=True)
type_ = fields.TypedField("type_", key_name="type", preset_hook=validate_artifact_type)
content_type = fields.TypedField("content_type")
content_type_version = fields.TypedField("content_type_version")
Expand Down Expand Up @@ -94,6 +112,7 @@ def __init__(self, data=None, type_=None):
# for `data` has access to this attribute.
self._packed_data = None
self.data = data
self.raw_artifact = RawArtifact()

@property
def data(self):
Expand Down Expand Up @@ -159,7 +178,8 @@ def to_obj(self, ns_info=None):
artifact_obj.Packaging = packaging

if self.packed_data:
artifact_obj.Raw_Artifact = RawArtifact(self.packed_data).to_obj(ns_info=ns_info)
self.raw_artifact.value = self.packed_data
artifact_obj.Raw_Artifact = self.raw_artifact.to_obj(ns_info=ns_info)

return artifact_obj

Expand All @@ -169,7 +189,8 @@ def to_dict(self):
if self.packaging:
artifact_dict['packaging'] = [p.to_dict() for p in self.packaging]
if self.packed_data:
artifact_dict['raw_artifact'] = RawArtifact(self.packed_data).to_dict()
self.raw_artifact.value = self.packed_data
artifact_dict['raw_artifact'] = self.raw_artifact.to_dict()

return artifact_dict

Expand All @@ -179,7 +200,7 @@ def from_obj(cls, cls_obj):
return None

artifact = super(Artifact, cls).from_obj(cls_obj)

packaging = cls_obj.Packaging
if packaging:
for c in packaging.Compression:
Expand All @@ -191,8 +212,8 @@ def from_obj(cls, cls_obj):

raw_artifact = cls_obj.Raw_Artifact
if raw_artifact:
data = RawArtifact.from_obj(raw_artifact).value
artifact.packed_data = six.text_type(data)
artifact.raw_artifact = RawArtifact.from_obj(raw_artifact)
artifact.packed_data = six.text_type(artifact.raw_artifact.value)

return artifact

Expand All @@ -202,7 +223,7 @@ def from_dict(cls, cls_dict):
return None

artifact = super(Artifact, cls).from_dict(cls_dict)

for layer in cls_dict.get('packaging', []):
if layer.get('packaging_type') == "compression":
artifact.packaging.append(CompressionFactory.from_dict(layer))
Expand All @@ -213,8 +234,8 @@ def from_dict(cls, cls_dict):

raw_artifact = cls_dict.get('raw_artifact')
if raw_artifact:
data = RawArtifact.from_dict(raw_artifact).value
artifact.packed_data = six.text_type(data)
artifact.raw_artifact = RawArtifact.from_dict(raw_artifact)
artifact.packed_data = six.text_type(artifact.raw_artifact.value)

return artifact

Expand All @@ -232,9 +253,10 @@ class Compression(Packaging):
compression_mechanism = fields.TypedField("compression_mechanism")
compression_mechanism_ref = fields.TypedField("compression_mechanism_ref")

def __init__(self, compression_mechanism=None):
def __init__(self, compression_mechanism=None, compression_mechanism_ref=None):
super(Compression, self).__init__()
self.compression_mechanism = compression_mechanism
self.compression_mechanism_ref = compression_mechanism_ref

def to_dict(self):
dict_ = super(Compression, self).to_dict()
Expand All @@ -244,7 +266,7 @@ def to_dict(self):

class ZlibCompression(Compression):
def __init__(self):
super(ZlibCompression, self).__init__("zlib")
super(ZlibCompression, self).__init__(compression_mechanism="zlib")

def pack(self, data):
return zlib.compress(data)
Expand All @@ -256,7 +278,7 @@ def unpack(self, packed_data):
class Bz2Compression(Compression):

def __init__(self):
super(Bz2Compression, self).__init__("bz2")
super(Bz2Compression, self).__init__(compression_mechanism="bz2")

def pack(self, data):
return bz2.compress(data)
Expand All @@ -278,10 +300,13 @@ class Encryption(Packaging):
encryption_key = fields.TypedField("encryption_key")
encryption_key_ref = fields.TypedField("encryption_key_ref")

def __init__(self, encryption_mechanism=None, encryption_key=None):
def __init__(self, encryption_mechanism=None, encryption_key=None,
encryption_mechanism_ref=None, encryption_key_ref=None):
super(Encryption, self).__init__()
self.encryption_mechanism = encryption_mechanism
self.encryption_key = encryption_key
self.encryption_mechanism_ref = encryption_mechanism_ref
self.encryption_key_ref = encryption_key_ref

def to_dict(self):
dict_ = super(Encryption, self).to_dict()
Expand All @@ -292,7 +317,10 @@ def to_dict(self):
class XOREncryption(Encryption):

def __init__(self, key=None):
super(XOREncryption, self).__init__("xor", key)
super(XOREncryption, self).__init__(
encryption_mechanism="xor",
encryption_key=key
)

def pack(self, data):
return xor(data, self.encryption_key)
Expand All @@ -303,7 +331,10 @@ def unpack(self, packed_data):

class PasswordProtectedZipEncryption(Encryption):
def __init__(self, key=None):
super(PasswordProtectedZipEncryption, self).__init__("PasswordProtected", key)
super(PasswordProtectedZipEncryption, self).__init__(
encryption_mechanism="PasswordProtected",
encryption_key=key
)

# `pack` is not implemented

Expand All @@ -330,6 +361,14 @@ class Encoding(Packaging):
_binding_class = _binding.EncodingType

algorithm = fields.TypedField("algorithm")
character_set = fields.TypedField("character_set")
custom_character_set_ref = fields.TypedField("custom_character_set_ref")

def __init__(self, algorithm=None, character_set=None, custom_character_set_ref=None):
super(Encoding, self).__init__()
self.algorithm = algorithm
self.character_set = character_set
self.custom_character_set_ref = custom_character_set_ref

def to_dict(self):
dict_ = super(Encoding, self).to_dict()
Expand All @@ -351,14 +390,14 @@ class EncryptionFactory(entities.EntityFactory):
def entity_class(cls, key):
if key == "xor":
return XOREncryption
elif key == 'PasswordProtected':
elif key == "PasswordProtected":
return PasswordProtectedZipEncryption
else:
raise ValueError("Unsupported encryption mechanism: %s" % key)

@classmethod
def dictkey(cls, mapping):
return mapping.get('encryption_mechanism')
return mapping.get("encryption_mechanism")

@classmethod
def objkey(cls, obj):
Expand All @@ -377,7 +416,7 @@ def entity_class(cls, key):

@classmethod
def dictkey(cls, mapping):
return mapping.get('compression_mechanism')
return mapping.get("compression_mechanism")

@classmethod
def objkey(cls, obj):
Expand All @@ -394,7 +433,7 @@ def entity_class(cls, key):

@classmethod
def dictkey(cls, mapping):
return mapping.get('algorithm', "Base64") # default is Base64
return mapping.get("algorithm", "Base64") # default is Base64

@classmethod
def objkey(cls, obj):
Expand Down
121 changes: 121 additions & 0 deletions cybox/test/objects/artifact_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,127 @@ def test_encryption(self):
self.assertEqual(self.binary_data, a2.data)


class TestArtifactInstance(ObjectTestCase, unittest.TestCase):
object_type = "ArtifactObjectType"
klass = Artifact

_full_dict = {
"packaging": [
{
"packaging_type": "encoding",
"algorithm": "Base64"
}
],
"xsi:type": object_type,
"raw_artifact": "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"
"AlgAECABBPgAAAACAAAAAAAAAA3ADAABAAEAAAJYAATMmLhYwWhKQrQ/CwBSAAAA"
"UgAAAADAnzJBjADgGLEMrQgARQAARAAAQABAEWU7wKiqCMCoqhSAHAA1ADACNVpT"
"AQAAAQAAAAAAAAExATABMAMxMjcHaW4tYWRkcgRhcnBhAAAMAAHBaEpCAEILAGkA"
"AABpAAAAAOAYsQytAMCfMkGMCABFAABb2PUAAIARjC7AqKoUwKiqCAA1gBwAR/kw"
"WlOFgAABAAEAAAAAATEBMAEwAzEyNwdpbi1hZGRyBGFycGEAAAwAAcAMAAwAAQAA"
"DhAACwlsb2NhbGhvc3QAwWhKQkZLCwBDAAAAQwAAAADAnzJBjADgGLEMrQgARQAA"
"NQAAQABAEWVKwKiqCMCoqhSAHQA1ACGYvSCKAQAAAQAAAAAAAANpc2MDb3JnAAAC"
"AAHBaEpC2ogLAIEAAACBAAAAABKpADIjAGAIReRVCABFAABzh94AAIARapXAqKo4"
"2Q0EGAarADUAXznwMm4BAAABAAAAAAAABV9sZGFwBF90Y3AXRGVmYXVsdC1GaXJz"
"dC1TaXRlLU5hbWUGX3NpdGVzAmRjBl9tc2Rjcwt1dGVsc3lzdGVtcwVsb2NhbAAA"
"IQABwWhKQrWSCwCmAAAApgAAAADgGLEMrQDAnzJBjAgARQAAmNj3AACAEYvvwKiq"
"FMCoqggANYAdAIR72CCKgYAAAQAEAAAAAANpc2MDb3JnAAACAAHADAACAAEAAA4Q"
"AA4GbnMtZXh0BG5ydDHADMAMAAIAAQAADhAADgZucy1leHQEc3RoMcAMwAwAAgAB"
"AAAOEAAJBm5zLWV4dMAMwAwAAgABAAAOEAAOBm5zLWV4dARsZ2ExwAzBaEpCPdYL"
"AIEAAACBAAAAAGAIReRVABKpADIjCABFAABzAABAADoR+HPZDQQYwKiqOAA1BqsA"
"X7VsMm6FgwABAAAAAAAABV9sZGFwBF90Y3AXRGVmYXVsdC1GaXJzdC1TaXRlLU5h"
"bWUGX3NpdGVzAmRjBl9tc2Rjcwt1dGVsc3lzdGVtcwVsb2NhbAAAIQABwWhKQszY"
"CwBiAAAAYgAAAAASqQAyIwBgCEXkVQgARQAAVIfwAACAEWqiwKiqONkNBBgGrAA1"
"AEB8UfFhAQAAAQAAAAAAAAVfbGRhcARfdGNwAmRjBl9tc2Rjcwt1dGVsc3lzdGVt"
"cwVsb2NhbAAAIQABwWhKQmEcDABiAAAAYgAAAABgCEXkVQASqQAyIwgARQAAVAAA"
"QAA6EfiS2Q0EGMCoqjgANQasAED3zfFhhYMAAQAAAAAAAAVfbGRhcARfdGNwAmRj"
"Bl9tc2Rjcwt1dGVsc3lzdGVtcwVsb2NhbAAAIQABwWhKQoAeDACMAAAAjAAAAAAS"
"qQAyIwBgCEXkVQgARQAAfofxAACAEWp3wKiqONkNBBgGrQA1AGp3mINhAQAAAQAA"
"AAAAAAVfbGRhcARfdGNwJDA1YjUyOTJiLTM0YjgtNGZiNy04NWEzLThiZWVmNWZk"
"MjA2OQdkb21haW5zBl9tc2Rjcwt1dGVsc3lzdGVtcwVsb2NhbAAAIQABwWhKQmRr"
"DACMAAAAjAAAAABgCEXkVQASqQAyIwgARQAAfgAAQAA6Efho2Q0EGMCoqjgANQat"
"AGrzFINhhYMAAQAAAAAAAAVfbGRhcARfdGNwJDA1YjUyOTJiLTM0YjgtNGZiNy04"
"NWEzLThiZWVmNWZkMjA2OQdkb21haW5zBl9tc2Rjcwt1dGVsc3lzdGVtcwVsb2Nh"
"bAAAIQABwWhKQvn4DQBTAAAAUwAAAAASqQAyIwBgCEXkVQgARQAARYf1AACAEWqs"
"wKiqONkNBBgGrgA1ADEajdBgAQAAAQAAAAAAAAVHUklNTQt1dGVsc3lzdGVtcwVs"
"b2NhbAAAAQABwWhKQhU7DgBTAAAAUwAAAABgCEXkVQASqQAyIwgARQAARQAAQAA6"
"Efih2Q0EGMCoqjgANQauADGWCdBghYMAAQAAAAAAAAVHUklNTQt1dGVsc3lzdGVt"
"cwVsb2NhbAAAAQAByWhKQuJzBQBTAAAAUwAAAAASqQAyIwBgCEXkVQgARQAARYf7"
"AACAEWqmwKiqONkNBBgGrwA1ADF0iXZjAQAAAQAAAAAAAAVHUklNTQt1dGVsc3lz"
"dGVtcwVsb2NhbAAAAQAByWhKQj+6BQBTAAAAUwAAAABgCEXkVQASqQAyIwgARQAA"
"RQAAQAA6Efih2Q0EGMCoqjgANQavADHwBXZjhYMAAQAAAAAAAAVHUklNTQt1dGVs"
"c3lzdGVtcwVsb2NhbAAAAQAB",
"type": "Network Traffic"
}


class TestArtifactPattern(ObjectTestCase, unittest.TestCase):
object_type = "ArtifactObjectType"
klass = Artifact

_full_dict = {
"xsi:type": object_type,
"raw_artifact": {
"value": "777777076578616D706C6503636F6D",
"condition": "Contains"
},
"type": "Network Traffic"
}


def _get_data(artifact):
return artifact.data

Expand Down

0 comments on commit 296df6e

Please sign in to comment.