commit
055bd7ad04
|
@ -135,6 +135,7 @@ _HASH_REGEX = {
|
||||||
"SHA3512": ("^[a-fA-F0-9]{128}$", "SHA3-512"),
|
"SHA3512": ("^[a-fA-F0-9]{128}$", "SHA3-512"),
|
||||||
"SSDEEP": ("^[a-zA-Z0-9/+:.]{1,128}$", "ssdeep"),
|
"SSDEEP": ("^[a-zA-Z0-9/+:.]{1,128}$", "ssdeep"),
|
||||||
"WHIRLPOOL": ("^[a-fA-F0-9]{128}$", "WHIRLPOOL"),
|
"WHIRLPOOL": ("^[a-fA-F0-9]{128}$", "WHIRLPOOL"),
|
||||||
|
"TLSH": ("^[a-fA-F0-9]{70}$", "TLSH"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -363,6 +363,10 @@ class DictionaryProperty(Property):
|
||||||
"underscore (_)"
|
"underscore (_)"
|
||||||
)
|
)
|
||||||
raise DictionaryKeyError(k, msg)
|
raise DictionaryKeyError(k, msg)
|
||||||
|
|
||||||
|
if len(dictified) < 1:
|
||||||
|
raise ValueError("must not be empty.")
|
||||||
|
|
||||||
return dictified
|
return dictified
|
||||||
|
|
||||||
|
|
||||||
|
@ -381,6 +385,7 @@ HASHES_REGEX = {
|
||||||
"SHA3512": (r"^[a-fA-F0-9]{128}$", "SHA3-512"),
|
"SHA3512": (r"^[a-fA-F0-9]{128}$", "SHA3-512"),
|
||||||
"SSDEEP": (r"^[a-zA-Z0-9/+:.]{1,128}$", "ssdeep"),
|
"SSDEEP": (r"^[a-zA-Z0-9/+:.]{1,128}$", "ssdeep"),
|
||||||
"WHIRLPOOL": (r"^[a-fA-F0-9]{128}$", "WHIRLPOOL"),
|
"WHIRLPOOL": (r"^[a-fA-F0-9]{128}$", "WHIRLPOOL"),
|
||||||
|
"TLSH": (r"^[a-fA-F0-9]{70}$", "TLSH"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ EXPECTED_BUNDLE = """{
|
||||||
],
|
],
|
||||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
"pattern_type": "stix",
|
"pattern_type": "stix",
|
||||||
|
"pattern_version": "2.1",
|
||||||
"valid_from": "2017-01-01T12:34:56Z"
|
"valid_from": "2017-01-01T12:34:56Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -61,6 +62,7 @@ EXPECTED_BUNDLE_DICT = {
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
"pattern_type": "stix",
|
"pattern_type": "stix",
|
||||||
|
"pattern_version": "2.1",
|
||||||
"valid_from": "2017-01-01T12:34:56Z",
|
"valid_from": "2017-01-01T12:34:56Z",
|
||||||
"indicator_types": [
|
"indicator_types": [
|
||||||
"malicious-activity",
|
"malicious-activity",
|
||||||
|
|
|
@ -19,6 +19,7 @@ EXPECTED_INDICATOR = """{
|
||||||
],
|
],
|
||||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
"pattern_type": "stix",
|
"pattern_type": "stix",
|
||||||
|
"pattern_version": "2.1",
|
||||||
"valid_from": "1970-01-01T00:00:01Z"
|
"valid_from": "1970-01-01T00:00:01Z"
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join("""
|
||||||
indicator_types=['malicious-activity'],
|
indicator_types=['malicious-activity'],
|
||||||
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
pattern_type='stix',
|
pattern_type='stix',
|
||||||
|
pattern_version='2.1',
|
||||||
valid_from='1970-01-01T00:00:01Z'
|
valid_from='1970-01-01T00:00:01Z'
|
||||||
""".split()) + ")"
|
""".split()) + ")"
|
||||||
|
|
||||||
|
|
|
@ -1117,6 +1117,28 @@ def test_network_traffic_socket_example():
|
||||||
assert nt.extensions['socket-ext'].socket_type == "SOCK_STREAM"
|
assert nt.extensions['socket-ext'].socket_type == "SOCK_STREAM"
|
||||||
|
|
||||||
|
|
||||||
|
def test_incorrect_socket_options():
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
stix2.v21.SocketExt(
|
||||||
|
is_listening=True,
|
||||||
|
address_family="AF_INET",
|
||||||
|
protocol_family="PF_INET",
|
||||||
|
socket_type="SOCK_STREAM",
|
||||||
|
options={"RCVTIMEO": 100},
|
||||||
|
)
|
||||||
|
assert "Incorrect options key" == str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
stix2.v21.SocketExt(
|
||||||
|
is_listening=True,
|
||||||
|
address_family="AF_INET",
|
||||||
|
protocol_family="PF_INET",
|
||||||
|
socket_type="SOCK_STREAM",
|
||||||
|
options={"SO_RCVTIMEO": '100'},
|
||||||
|
)
|
||||||
|
assert "Options value must be an integer" == str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
def test_network_traffic_tcp_example():
|
def test_network_traffic_tcp_example():
|
||||||
h = stix2.v21.TCPExt(src_flags_hex="00000002")
|
h = stix2.v21.TCPExt(src_flags_hex="00000002")
|
||||||
nt = stix2.v21.NetworkTraffic(
|
nt = stix2.v21.NetworkTraffic(
|
||||||
|
@ -1366,6 +1388,18 @@ def test_x509_certificate_example():
|
||||||
assert x509.subject == "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org" # noqa
|
assert x509.subject == "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org" # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def test_x509_certificate_error():
|
||||||
|
|
||||||
|
with pytest.raises(stix2.exceptions.PropertyPresenceError) as excinfo:
|
||||||
|
stix2.v21.X509Certificate(
|
||||||
|
defanged=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.v21.X509Certificate
|
||||||
|
assert "At least one of the" in str(excinfo.value)
|
||||||
|
assert "properties for X509Certificate must be populated." in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
def test_new_version_with_related_objects():
|
def test_new_version_with_related_objects():
|
||||||
data = stix2.v21.ObservedData(
|
data = stix2.v21.ObservedData(
|
||||||
first_observed="2016-03-12T12:00:00Z",
|
first_observed="2016-03-12T12:00:00Z",
|
||||||
|
|
|
@ -72,6 +72,14 @@ def test_list_property():
|
||||||
p.clean([])
|
p.clean([])
|
||||||
|
|
||||||
|
|
||||||
|
def test_dictionary_property():
|
||||||
|
p = DictionaryProperty(StringProperty)
|
||||||
|
|
||||||
|
assert p.clean({'spec_version': '2.1'})
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.clean({})
|
||||||
|
|
||||||
|
|
||||||
def test_string_property():
|
def test_string_property():
|
||||||
prop = StringProperty()
|
prop = StringProperty()
|
||||||
|
|
||||||
|
@ -411,6 +419,7 @@ def test_property_list_of_dictionary():
|
||||||
"value", [
|
"value", [
|
||||||
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
|
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
|
||||||
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
|
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
|
||||||
|
[('TLSH', '6FF02BEF718027B0160B4391212923ED7F1A463D563B1549B86CF62973B197AD2731F8')],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_hashes_property_valid(value):
|
def test_hashes_property_valid(value):
|
||||||
|
@ -422,6 +431,7 @@ def test_hashes_property_valid(value):
|
||||||
"value", [
|
"value", [
|
||||||
{"MD5": "a"},
|
{"MD5": "a"},
|
||||||
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
|
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
|
||||||
|
{"TLSH": "6FF02BEF718027B0160B4391212923ED7F1A463D563B1549B86CF62973B197AD2731F"},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_hashes_property_invalid(value):
|
def test_hashes_property_invalid(value):
|
||||||
|
|
|
@ -592,6 +592,18 @@ class SocketExt(_Extension):
|
||||||
('socket_handle', IntegerProperty()),
|
('socket_handle', IntegerProperty()),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def _check_object_constraints(self):
|
||||||
|
super(SocketExt, self)._check_object_constraints()
|
||||||
|
|
||||||
|
options = self.get('options')
|
||||||
|
|
||||||
|
if options is not None:
|
||||||
|
for key, val in options.items():
|
||||||
|
if key[:3] != "SO_":
|
||||||
|
raise ValueError("Incorrect options key")
|
||||||
|
if not isinstance(val, int):
|
||||||
|
raise ValueError("Options value must be an integer")
|
||||||
|
|
||||||
|
|
||||||
class TCPExt(_Extension):
|
class TCPExt(_Extension):
|
||||||
# TODO: Add link
|
# TODO: Add link
|
||||||
|
@ -986,6 +998,18 @@ class X509Certificate(_Observable):
|
||||||
])
|
])
|
||||||
_id_contributing_properties = ["hashes", "serial_number"]
|
_id_contributing_properties = ["hashes", "serial_number"]
|
||||||
|
|
||||||
|
def _check_object_constraints(self):
|
||||||
|
super(X509Certificate, self)._check_object_constraints()
|
||||||
|
|
||||||
|
att_list = [
|
||||||
|
'is_self_signed', 'hashes', 'version', 'serial_number',
|
||||||
|
'signature_algorithm', 'issuer', 'validity_not_before',
|
||||||
|
'validity_not_after', 'subject', 'subject_public_key_algorithm',
|
||||||
|
'subject_public_key_modulus', 'subject_public_key_exponent',
|
||||||
|
'x509_v3_extensions',
|
||||||
|
]
|
||||||
|
self._check_at_least_one_property(att_list)
|
||||||
|
|
||||||
|
|
||||||
def CustomObservable(type='x-custom-observable', properties=None):
|
def CustomObservable(type='x-custom-observable', properties=None):
|
||||||
"""Custom STIX Cyber Observable Object type decorator.
|
"""Custom STIX Cyber Observable Object type decorator.
|
||||||
|
|
|
@ -215,6 +215,13 @@ class Indicator(STIXDomainObject):
|
||||||
('granular_markings', ListProperty(GranularMarking)),
|
('granular_markings', ListProperty(GranularMarking)),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
if kwargs.get('pattern') and kwargs.get('pattern_type') == 'stix' and not kwargs.get('pattern_version'):
|
||||||
|
kwargs['pattern_version'] = '2.1'
|
||||||
|
|
||||||
|
super(STIXDomainObject, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def _check_object_constraints(self):
|
def _check_object_constraints(self):
|
||||||
super(Indicator, self)._check_object_constraints()
|
super(Indicator, self)._check_object_constraints()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue