def assertPattern(self, stix_pattern):
        errors = pattern_validator(stix_pattern, stix_version='2.1')

        # print('\nPattern:', stix_pattern)
        # print('Errors', errors)

        assert len(errors) == 0
Example #2
0
def patterns(instance):
    """Ensure that the syntax of the pattern of an indicator is valid.
    """
    if instance['type'] != 'indicator' or 'pattern' not in instance:
        return

    pattern = instance['pattern']
    errors = pattern_validator(pattern)

    for e in errors:
        yield JSONError("Pattern failed to validate: %s."
                        % e, instance['id'])
Example #3
0
def patterns(instance, options):
    """Ensure that the syntax of the pattern of an indicator is valid, and that
    objects and properties referenced by the pattern are valid.
    """
    if instance['type'] != 'indicator' or 'pattern' not in instance:
        return

    pattern = instance['pattern']
    if not isinstance(pattern, string_types):
        return  # This error already caught by schemas
    errors = pattern_validator(pattern, stix_version='2.0')

    # Check pattern syntax
    if errors:
        for e in errors:
            yield PatternError(str(e), instance['id'])
        return

    type_format_re = re.compile(r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$')
    property_format_re = re.compile(r'^[a-z0-9_]{3,250}$')

    p = Pattern(pattern)
    inspection = p.inspect().comparisons
    for objtype in inspection:
        # Check observable object types
        if objtype in enums.OBSERVABLE_TYPES:
            pass
        elif (not type_format_re.match(objtype) or
              len(objtype) < 3 or len(objtype) > 250):
            yield PatternError("'%s' is not a valid observable type name"
                               % objtype, instance['id'])
        elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix']) and
              not CUSTOM_TYPE_PREFIX_RE.match(objtype)):
            yield PatternError("Custom Observable Object type '%s' should start "
                               "with 'x-' followed by a source unique identifier "
                               "(like a domain name with dots replaced by "
                               "hyphens), a hyphen and then the name"
                               % objtype, instance['id'])
        elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix-lax']) and
              not CUSTOM_TYPE_LAX_PREFIX_RE.match(objtype)):
            yield PatternError("Custom Observable Object type '%s' should start "
                               "with 'x-'" % objtype, instance['id'])

        # Check observable object properties
        expression_list = inspection[objtype]
        for exp in expression_list:
            path = exp[0]
            # Get the property name without list index, dictionary key, or referenced object property
            prop = path[0]
            if objtype in enums.OBSERVABLE_PROPERTIES and prop in enums.OBSERVABLE_PROPERTIES[objtype]:
                continue
            elif not property_format_re.match(prop):
                yield PatternError("'%s' is not a valid observable property name"
                                   % prop, instance['id'])
            elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix']) and
                  not CUSTOM_PROPERTY_PREFIX_RE.match(prop)):
                yield PatternError("Cyber Observable Object custom property '%s' "
                                   "should start with 'x_' followed by a source "
                                   "unique identifier (like a domain name with "
                                   "dots replaced by underscores), an "
                                   "underscore and then the name"
                                   % prop, instance['id'])
            elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix-lax']) and
                  not CUSTOM_PROPERTY_LAX_PREFIX_RE.match(prop)):
                yield PatternError("Cyber Observable Object custom property '%s' "
                                   "should start with 'x_'" % prop, instance['id'])
def patterns(instance, options):
    """Ensure that the syntax of the pattern of an indicator is valid, and that
    objects and properties referenced by the pattern are valid.
    """
    if (instance['type'] != 'indicator' or instance.get('pattern_type', '') != 'stix' or
            isinstance(instance.get('pattern', None), str) is False):
        return

    pattern = instance['pattern']
    if 'pattern_version' in instance:
        pattern_version = instance['pattern_version']
    elif 'spec_version' in instance:
        pattern_version = instance['spec_version']
    else:
        pattern_version = '2.1'
    errors = pattern_validator(pattern, pattern_version)

    # Check pattern syntax
    if errors:
        for e in errors:
            yield PatternError(str(e), instance['id'])
        return

    p = Pattern(pattern)
    inspection = p.inspect().comparisons
    for objtype in inspection:
        # Check observable object types
        if objtype in enums.OBSERVABLE_TYPES:
            pass
        elif (not TYPE_FORMAT_RE.match(objtype) or
              len(objtype) < 3 or len(objtype) > 250):
            yield PatternError("'%s' is not a valid observable type name"
                               % objtype, instance['id'])
        elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix']) and
              'extensions-use' in options.disabled and not CUSTOM_TYPE_PREFIX_RE.match(objtype)):
            yield PatternError("Custom Observable Object type '%s' should start "
                               "with 'x-' followed by a source unique identifier "
                               "(like a domain name with dots replaced by "
                               "hyphens), a hyphen and then the name"
                               % objtype, instance['id'])
        elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix-lax']) and
              'extensions-use' in options.disabled and not CUSTOM_TYPE_LAX_PREFIX_RE.match(objtype)):
            yield PatternError("Custom Observable Object type '%s' should start "
                               "with 'x-'" % objtype, instance['id'])

        # Check observable object properties
        expression_list = inspection[objtype]
        for exp in expression_list:
            path = exp[0]
            # Get the property name without list index, dictionary key, or referenced object property
            prop = path[0]
            if objtype in enums.OBSERVABLE_PROPERTIES and prop in enums.OBSERVABLE_PROPERTIES[objtype]:
                continue
            elif not PROPERTY_FORMAT_RE.match(prop):
                yield PatternError("'%s' is not a valid observable property name"
                                   % prop, instance['id'])
            elif objtype not in enums.OBSERVABLE_TYPES:
                continue  # custom SCOs aren't required to use x_ prefix on properties
            elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix']) and
                  'extensions-use' in options.disabled and not CUSTOM_PROPERTY_PREFIX_RE.match(prop)):
                yield PatternError("Cyber Observable Object custom property '%s' "
                                   "should start with 'x_' followed by a source "
                                   "unique identifier (like a domain name with "
                                   "dots replaced by underscores), an "
                                   "underscore and then the name"
                                   % prop, instance['id'])
            elif (all(x not in options.disabled for x in ['all', 'format-checks', 'custom-prefix-lax']) and
                  'extensions-use' in options.disabled and not CUSTOM_PROPERTY_LAX_PREFIX_RE.match(prop)):
                yield PatternError("Cyber Observable Object custom property '%s' "
                                   "should start with 'x_'" % prop, instance['id'])