diff --git a/stix2/properties.py b/stix2/properties.py index ee6a62ef..bcd21f97 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -18,8 +18,8 @@ # This uses the regular expression for a RFC 4122, Version 4 UUID. In the # 8-4-4-4-12 hexadecimal representation, the first hex digit of the third -# component must be a 4, and the first hex digit of the fourth component must be -# 8, 9, a, or b (10xx bit pattern). +# component must be a 4, and the first hex digit of the fourth component +# must be 8, 9, a, or b (10xx bit pattern). ID_REGEX = re.compile("^[a-z0-9][a-z0-9-]+[a-z0-9]--" # object type "[0-9a-fA-F]{8}-" "[0-9a-fA-F]{4}-" @@ -39,14 +39,15 @@ class Property(object): ``__init__()``. Args: - required (bool): If ``True``, the property must be provided when creating an - object with that property. No default value exists for these properties. - (Default: ``False``) + required (bool): If ``True``, the property must be provided when + creating an object with that property. No default value exists for + these properties. (Default: ``False``) fixed: This provides a constant default value. Users are free to - provide this value explicity when constructing an object (which allows - you to copy **all** values from an existing object to a new object), but - if the user provides a value other than the ``fixed`` value, it will raise - an error. This is semantically equivalent to defining both: + provide this value explicity when constructing an object (which + allows you to copy **all** values from an existing object to a new + object), but if the user provides a value other than the ``fixed`` + value, it will raise an error. This is semantically equivalent to + defining both: - a ``clean()`` function that checks if the value matches the fixed value, and @@ -57,29 +58,31 @@ class Property(object): - ``def clean(self, value) -> any:`` - Return a value that is valid for this property. If ``value`` is not valid for this property, this will attempt to transform it first. If - ``value`` is not valid and no such transformation is possible, it should - raise a ValueError. + ``value`` is not valid and no such transformation is possible, it + should raise a ValueError. - ``def default(self):`` - provide a default value for this property. - ``default()`` can return the special value ``NOW`` to use the current - time. This is useful when several timestamps in the same object need - to use the same default value, so calling now() for each property-- - likely several microseconds apart-- does not work. - - Subclasses can instead provide a lambda function for ``default`` as a keyword - argument. ``clean`` should not be provided as a lambda since lambdas cannot - raise their own exceptions. - - When instantiating Properties, ``required`` and ``default`` should not be used - together. ``default`` implies that the property is required in the specification - so this function will be used to supply a value if none is provided. - ``required`` means that the user must provide this; it is required in the - specification and we can't or don't want to create a default value. + time. This is useful when several timestamps in the same object + need to use the same default value, so calling now() for each + property-- likely several microseconds apart-- does not work. + + Subclasses can instead provide a lambda function for ``default`` as a + keyword argument. ``clean`` should not be provided as a lambda since + lambdas cannot raise their own exceptions. + + When instantiating Properties, ``required`` and ``default`` should not be + used together. ``default`` implies that the property is required in the + specification so this function will be used to supply a value if none is + provided. ``required`` means that the user must provide this; it is + required in the specification and we can't or don't want to create a + default value. + """ def _default_clean(self, value): if value != self._fixed_value: - raise ValueError("must equal '{0}'.".format(self._fixed_value)) + raise ValueError("must equal '{}'.".format(self._fixed_value)) return value def __init__(self, required=False, fixed=None, default=None): @@ -186,7 +189,7 @@ def __init__(self, type): def clean(self, value): if not value.startswith(self.required_prefix): - raise ValueError("must start with '{0}'.".format(self.required_prefix)) + raise ValueError("must start with '{}'.".format(self.required_prefix)) if not ID_REGEX.match(value): raise ValueError(ERROR_INVALID_ID) return value @@ -219,8 +222,8 @@ def clean(self, value): if isinstance(value, bool): return value - trues = ['true', 't'] - falses = ['false', 'f'] + trues = ['true', 't', '1'] + falses = ['false', 'f', '0'] try: if value.lower() in trues: return True @@ -302,7 +305,7 @@ def clean(self, value): if key in HASHES_REGEX: vocab_key = HASHES_REGEX[key][1] if not re.match(HASHES_REGEX[key][0], v): - raise ValueError("'%s' is not a valid %s hash" % (v, vocab_key)) + raise ValueError("'{0}' is not a valid {1} hash".format(v, vocab_key)) if k != vocab_key: clean_dict[vocab_key] = clean_dict[k] del clean_dict[k] @@ -342,7 +345,7 @@ def clean(self, value): value = str(value) if self.type: if not value.startswith(self.type): - raise ValueError("must start with '{0}'.".format(self.type)) + raise ValueError("must start with '{}'.".format(self.type)) if not ID_REGEX.match(value): raise ValueError(ERROR_INVALID_ID) return value @@ -378,7 +381,7 @@ def clean(self, value): if type(value) is dict: value = self.type(**value) elif not isinstance(value, self.type): - raise ValueError("must be of type %s." % self.type.__name__) + raise ValueError("must be of type {}.".format(self.type.__name__)) return value @@ -393,7 +396,7 @@ def __init__(self, allowed, **kwargs): def clean(self, value): value = super(EnumProperty, self).clean(value) if value not in self.allowed: - raise ValueError("value '%s' is not valid for this enumeration." % value) + raise ValueError("value '{}' is not valid for this enumeration.".format(value)) return self.string_type(value) @@ -483,7 +486,7 @@ def clean(self, value): else: raise CustomContentError("Can't parse unknown extension type: {}".format(key)) else: - raise ValueError("The enclosing type '%s' has no extensions defined" % self.enclosing_type) + raise ValueError("The enclosing type '{}' has no extensions defined".format(self.enclosing_type)) return dictified diff --git a/stix2/v21/common.py b/stix2/v21/common.py index e822d42d..8c279960 100644 --- a/stix2/v21/common.py +++ b/stix2/v21/common.py @@ -22,7 +22,7 @@ class ExternalReference(_STIXBase): ('source_name', StringProperty(required=True)), ('description', StringProperty()), ('url', StringProperty()), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), ('external_id', StringProperty()), ]) diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index c5db7cff..9dc19028 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -31,7 +31,9 @@ class Artifact(_Observable): ('mime_type', StringProperty()), ('payload_bin', BinaryProperty()), ('url', StringProperty()), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), + ('encryption_algorithm', StringProperty()), + ('decryption_key', StringProperty()), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ]) @@ -182,7 +184,7 @@ class AlternateDataStream(_STIXBase): _properties = OrderedDict([ ('name', StringProperty(required=True)), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), ('size', IntegerProperty()), ]) @@ -269,7 +271,7 @@ class WindowsPEOptionalHeaderType(_STIXBase): ('size_of_heap_commit', IntegerProperty()), ('loader_flags_hex', HexProperty()), ('number_of_rva_and_sizes', IntegerProperty()), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), ]) def _check_object_constraints(self): @@ -287,7 +289,7 @@ class WindowsPESection(_STIXBase): ('name', StringProperty(required=True)), ('size', IntegerProperty()), ('entropy', FloatProperty()), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), ]) @@ -308,7 +310,7 @@ class WindowsPEBinaryExt(_Extension): ('number_of_symbols', IntegerProperty()), ('size_of_optional_header', IntegerProperty()), ('characteristics_hex', HexProperty()), - ('file_header_hashes', HashesProperty()), + ('file_header_hashes', HashesProperty(spec_version='2.1')), ('optional_header', EmbeddedObjectProperty(type=WindowsPEOptionalHeaderType)), ('sections', ListProperty(EmbeddedObjectProperty(type=WindowsPESection))), ]) @@ -323,7 +325,7 @@ class File(_Observable): _type = 'file' _properties = OrderedDict([ ('type', TypeProperty(_type)), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), ('size', IntegerProperty()), ('name', StringProperty()), ('name_enc', StringProperty()), @@ -334,9 +336,6 @@ class File(_Observable): ('modified', TimestampProperty()), ('accessed', TimestampProperty()), ('parent_directory_ref', ObjectReferenceProperty(valid_types='directory')), - ('is_encrypted', BooleanProperty()), - ('encryption_algorithm', StringProperty()), - ('decryption_key', StringProperty()), ('contains_refs', ListProperty(ObjectReferenceProperty)), ('content_ref', ObjectReferenceProperty(valid_types='artifact')), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), @@ -344,7 +343,6 @@ class File(_Observable): def _check_object_constraints(self): super(File, self)._check_object_constraints() - self._check_properties_dependency(['is_encrypted'], ['encryption_algorithm', 'decryption_key']) self._check_at_least_one_property(['hashes', 'name']) @@ -551,7 +549,7 @@ class WindowsServiceExt(_Extension): _type = 'windows-service-ext' _properties = OrderedDict([ - ('service_name', StringProperty(required=True)), + ('service_name', StringProperty()), ('descriptions', ListProperty(StringProperty)), ('display_name', StringProperty()), ('group_name', StringProperty()), @@ -601,7 +599,7 @@ class Process(_Observable): ('environment_variables', DictionaryProperty(spec_version='2.1')), ('opened_connection_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))), ('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')), - ('binary_ref', ObjectReferenceProperty(valid_types='file')), + ('image_ref', ObjectReferenceProperty(valid_types='file')), ('parent_ref', ObjectReferenceProperty(valid_types='process')), ('child_refs', ListProperty(ObjectReferenceProperty('process'))), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), @@ -678,7 +676,8 @@ class UserAccount(_Observable): _type = 'user-account' _properties = OrderedDict([ ('type', TypeProperty(_type)), - ('user_id', StringProperty(required=True)), + ('user_id', StringProperty()), + ('credential', StringProperty()), ('account_login', StringProperty()), ('account_type', StringProperty()), # open vocab ('display_name', StringProperty()), @@ -688,7 +687,7 @@ class UserAccount(_Observable): ('is_disabled', BooleanProperty()), ('account_created', TimestampProperty()), ('account_expires', TimestampProperty()), - ('password_last_changed', TimestampProperty()), + ('credential_last_changed', TimestampProperty()), ('account_first_login', TimestampProperty()), ('account_last_login', TimestampProperty()), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), @@ -703,7 +702,7 @@ class WindowsRegistryValueType(_STIXBase): _type = 'windows-registry-value-type' _properties = OrderedDict([ - ('name', StringProperty(required=True)), + ('name', StringProperty()), ('data', StringProperty()), ('data_type', EnumProperty(allowed=[ "REG_NONE", @@ -732,7 +731,7 @@ class WindowsRegistryKey(_Observable): _type = 'windows-registry-key' _properties = OrderedDict([ ('type', TypeProperty(_type)), - ('key', StringProperty(required=True)), + ('key', StringProperty()), ('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))), # this is not the modified timestamps of the object itself ('modified', TimestampProperty()), @@ -784,7 +783,7 @@ class X509Certificate(_Observable): _properties = OrderedDict([ ('type', TypeProperty(_type)), ('is_self_signed', BooleanProperty()), - ('hashes', HashesProperty()), + ('hashes', HashesProperty(spec_version='2.1')), ('version', StringProperty()), ('serial_number', StringProperty()), ('signature_algorithm', StringProperty()), diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index f8266a83..3e6e1a56 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -143,13 +143,14 @@ class Indicator(STIXDomainObject): ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('name', StringProperty()), + ('indicator_types', ListProperty(StringProperty, required=True)), ('description', StringProperty()), ('pattern', PatternProperty(required=True)), ('valid_from', TimestampProperty(default=lambda: NOW)), ('valid_until', TimestampProperty()), ('kill_chain_phases', ListProperty(KillChainPhase)), ('revoked', BooleanProperty(default=lambda: False)), - ('labels', ListProperty(StringProperty, required=True)), + ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), ('lang', StringProperty()), ('external_references', ListProperty(ExternalReference)), @@ -263,17 +264,11 @@ class Malware(STIXDomainObject): ('created_by_ref', ReferenceProperty(type='identity')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), + ('is_family', BooleanProperty(required=True)), ('name', StringProperty(required=True)), + ('malware_types', ListProperty(StringProperty, required=True)), ('description', StringProperty()), ('kill_chain_phases', ListProperty(KillChainPhase)), - ('revoked', BooleanProperty(default=lambda: False)), - ('labels', ListProperty(StringProperty, required=True)), - ('confidence', IntegerProperty()), - ('lang', StringProperty()), - ('external_references', ListProperty(ExternalReference)), - ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), - ('granular_markings', ListProperty(GranularMarking)), - ('is_family', BooleanProperty(required=True)), ('first_seen', TimestampProperty()), ('last_seen', TimestampProperty()), ('os_execution_envs', ListProperty(StringProperty)), @@ -283,7 +278,14 @@ class Malware(STIXDomainObject): ('static_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))), ('dynamic_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))), ('av_results', ListProperty(EmbeddedObjectProperty(AVResultsType))), - ('capabilities', ListProperty(StringProperty)) + ('capabilities', ListProperty(StringProperty)), + ('revoked', BooleanProperty(default=lambda: False)), + ('labels', ListProperty(StringProperty)), + ('confidence', IntegerProperty()), + ('lang', StringProperty()), + ('external_references', ListProperty(ExternalReference)), + ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), + ('granular_markings', ListProperty(GranularMarking)) ]) @@ -398,11 +400,12 @@ class Report(STIXDomainObject): ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('name', StringProperty(required=True)), + ('report_types', ListProperty(StringProperty, required=True)), ('description', StringProperty()), ('published', TimestampProperty(required=True)), ('object_refs', ListProperty(ReferenceProperty, required=True)), ('revoked', BooleanProperty(default=lambda: False)), - ('labels', ListProperty(StringProperty, required=True)), + ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), ('lang', StringProperty()), ('external_references', ListProperty(ExternalReference)), @@ -426,6 +429,7 @@ class ThreatActor(STIXDomainObject): ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('name', StringProperty(required=True)), + ('threat_actor_types', ListProperty(StringProperty, required=True)), ('description', StringProperty()), ('aliases', ListProperty(StringProperty)), ('roles', ListProperty(StringProperty)), @@ -436,7 +440,7 @@ class ThreatActor(STIXDomainObject): ('secondary_motivations', ListProperty(StringProperty)), ('personal_motivations', ListProperty(StringProperty)), ('revoked', BooleanProperty(default=lambda: False)), - ('labels', ListProperty(StringProperty, required=True)), + ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), ('lang', StringProperty()), ('external_references', ListProperty(ExternalReference)), @@ -460,11 +464,12 @@ class Tool(STIXDomainObject): ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('name', StringProperty(required=True)), + ('tool_types', ListProperty(StringProperty, required=True)), ('description', StringProperty()), ('kill_chain_phases', ListProperty(KillChainPhase)), ('tool_version', StringProperty()), ('revoked', BooleanProperty(default=lambda: False)), - ('labels', ListProperty(StringProperty, required=True)), + ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), ('lang', StringProperty()), ('external_references', ListProperty(ExternalReference)),