Repository: oasis-open/cti-stix-validator

Issue:
Fix Socket Options warning
The following warning was seen in the elevator for a valid socket option:

> The 'options' property of object 'network-traffic--eedcb05c-d030-5b59-9657-9fe758867611' contains a key ('IP_MULTICAST_LOOP') that is not a valid socket option (SO_*). 

The warning message doesn't accurately reflect what is being checked, and we leave out IP* and MCAST* options.

Comments:

Patch:
diff --git a/docs/best-practices.rst b/docs/best-practices.rst
index e9cf8a1..16782ed 100644
--- a/docs/best-practices.rst
+++ b/docs/best-practices.rst
@@ -154,6 +154,9 @@ Check Codes - STIX 2.1
 |  244   | account-type                | certain property values are from the   |
 |        |                             | account-type vocabulary                |
 +--------+-----------------------------+----------------------------------------+
+|  245   | indicator-pattern-types     | certain property values are from the   |
+|        |                             | pattern-type vocabulary                |
++--------+-----------------------------+----------------------------------------+
 |  270   | all-external-sources        | all of the following external source   |
 |        |                             | checks are run                         |
 +--------+-----------------------------+----------------------------------------+
diff --git a/stix2validator/schemas-2.1 b/stix2validator/schemas-2.1
index 61ee50e..5d0d5a2 160000
--- a/stix2validator/schemas-2.1
+++ b/stix2validator/schemas-2.1
@@ -1,1 +1,1 @@
-Subproject commit 61ee50e5d4e9c69b2b878da9596bd79638cd9054
+Subproject commit 5d0d5a2ee364215acb1f15db0016f3c1c17360bc
diff --git a/stix2validator/util.py b/stix2validator/util.py
index e3b0398..29654cb 100644
--- a/stix2validator/util.py
+++ b/stix2validator/util.py
@@ -106,6 +106,8 @@ https://stix2-validator.readthedocs.io/en/latest/best-practices.html.
 |      |                             | windows-pebinary-type vocabulary       |
 | 244  | account-type                | certain property values are from the   |
 |      |                             | account-type vocabulary                |
+| 245  | indicator-pattern-types     | certain property values are from the   |
+|      |                             | pattern-type vocabulary                |
 | 270  | all-external-sources        | all of the following external source   |
 |      |                             | checks are run                         |
 | 271  | mime-type                   | file.mime_type is a valid IANA MIME    |
diff --git a/stix2validator/v21/enums.py b/stix2validator/v21/enums.py
index 5737ad1..5fe7172 100644
--- a/stix2validator/v21/enums.py
+++ b/stix2validator/v21/enums.py
@@ -188,6 +188,14 @@ MALWARE_CAPABILITIES_OV = [
     "steals-authentication-credentials",
     "violates-system-operational-integrity",
 ]
+INDICATOR_PATTERN_OV = [
+    "stix",
+    "pcre",
+    "sigma",
+    "snort",
+    "suricata",
+    "yara",
+]
 PROCESSOR_ARCHITECTURE_OV = [
     "alpha",
     "arm",
@@ -286,19 +294,13 @@ TOOL_TYPE_OV = [
 ]
 HASH_ALGO_OV = [
     "MD5",
-    "MD6",
-    "RIPEMD-160",
     "SHA-1",
-    "SHA-224",
     "SHA-256",
-    "SHA-384",
     "SHA-512",
-    "SHA3-224",
     "SHA3-256",
-    "SHA3-384",
     "SHA3-512",
-    "ssdeep",
-    "WHIRLPOOL",
+    "SSDEEP",
+    "TLSH",
 ]
 WINDOWS_PEBINARY_TYPE_OV = [
     "exe",
@@ -365,6 +367,9 @@ IMPLEMENTATION_LANGUAGES_USES = {
 INDICATOR_TYPE_USES = {
     "indicator": ["indicator_types"],
 }
+INDICATOR_PATTERN_USES = {
+    "indicator": ["pattern_type"],
+}
 INFRASTRUCTURE_TYPE_USES = {
     "infrastructure": ["infrastructure_types"],
 }
@@ -2112,6 +2117,7 @@ CHECK_CODES = {
     '241': 'hash-algo',
     '243': 'windows-pebinary-type',
     '244': 'account-type',
+    '245': 'indicator-pattern-types',
     '270': 'all-external-sources',
     '271': 'mime-type',
     '272': 'protocols',
@@ -2253,34 +2259,202 @@ def ipfix():
     return ipfix.ipflist
 
 
+# If you have a Socket Option not present in this list
+# for SO|ICMP|ICMP6|IP|IPV6|MCAST|TCP|IRLMP please open an issue/PR
+# in https://github.com/oasis-open/cti-stix-validator/ to include it.
+# Include a reference (link) to where its defined.
 SOCKET_OPTIONS = [
+    'ICMP6_FILTER',
+    'IP_ADD_MEMBERSHIP',
+    'IP_ADD_SOURCE_MEMBERSHIP',
+    'IP_BIND_ADDRESS_NO_PORT',
+    'IP_BLOCK_SOURCE',
+    'IP_DONTFRAGMENT',
+    'IP_DROP_MEMBERSHIP',
+    'IP_DROP_SOURCE_MEMBERSHIP',
+    'IP_FREEBIND',
+    'IP_HDRINCL',
+    'IP_MSFILTER',
+    'IP_MTU',
+    'IP_MTU_DISCOVER',
+    'IP_MULTICAST_ALL',
+    'IP_MULTICAST_IF',
+    'IP_MULTICAST_LOOP',
+    'IP_MULTICAST_TTL',
+    'IP_NODEFRAG',
+    'IP_OPTIONS',
+    'IP_ORIGINAL_ARRIVAL_IF',
+    'IP_PKTINFO',
+    'IP_RECEIVE_BROADCAST',
+    'IP_RECVDSTADDR',
+    'IP_RECVERR',
+    'IP_RECVIF',
+    'IP_RECVOPTS',
+    'IP_RECVORIGDSTADDR',
+    'IP_RECVTOS',
+    'IP_RECVTTL',
+    'IP_RETOPTS',
+    'IP_ROUTER_ALERT',
+    'IP_TOS',
+    'IP_TRANSPARENT',
+    'IP_TTL',
+    'IP_UNBLOCK_SOURCE',
+    'IP_UNICAST_IF',
+    'IP_WFP_REDIRECT_CONTEXT',
+    'IP_WFP_REDIRECT_RECORDS',
+    'IPV6_ADD_MEMBERSHIP',
+    'IPV6_CHECKSUM',
+    'IPV6_DONTFRAG',
+    'IPV6_DROP_MEMBERSHIP',
+    'IPV6_DSTOPTS',
+    'IPV6_HDRINCL',
+    'IPV6_HOPLIMIT',
+    'IPV6_HOPOPTS',
+    'IPV6_JOIN_GROUP',
+    'IPV6_LEAVE_GROUP',
+    'IPV6_MTU',
+    'IPV6_MTU_DISCOVER',
+    'IPV6_MULTICAST_HOPS',
+    'IPV6_MULTICAST_IF',
+    'IPV6_MULTICAST_LOOP',
+    'IPV6_NEXTHOP',
+    'IPV6_PATHMTU',
+    'IPV6_PKTINFO',
+    'IPV6_PROTECTION_LEVEL',
+    'IPV6_RECVDSTOPTS',
+    'IPV6_RECVHOPLIMIT',
+    'IPV6_RECVHOPOPTS',
+    'IPV6_RECVIF',
+    'IPV6_RECVPATHMTU',
+    'IPV6_RECVPKTINFO',
+    'IPV6_RECVRTHDR',
+    'IPV6_RECVTCLASS',
+    'IPV6_RTHDR',
+    'IPV6_TCLASS',
+    'IPV6_UNICAST_HOPS',
+    'IPV6_UNICAST_IF',
+    'IPV6_UNICAT_HOPS',
+    'IPV6_USE_MIN_MTU',
+    'IPV6_V6ONLY',
+    'IRLMP_9WIRE_MODE',
+    'IRLMP_DISCOVERY_MODE',
+    'IRLMP_ENUMDEVICES',
+    'IRLMP_EXCLUSIVE_MODE',
+    'IRLMP_IAS_QUERY',
+    'IRLMP_IAS_SET',
+    'IRLMP_IRLPT_MODE',
+    'IRLMP_PARAMETERS',
+    'IRLMP_SEND_PDU_LEN',
+    'IRLMP_SHARP_MODE',
+    'IRLMP_TINYTP_MODE',
+    'MCAST_BLOCK_SOURCE',
+    'MCAST_JOIN_GROUP',
+    'MCAST_JOIN_SOURCE_GROUP',
+    'MCAST_LEAVE_GROUP',
+    'MCAST_LEAVE_SOURCE_GROUP',
+    'MCAST_UNBLOCK_SOURCE',
     'SO_ACCEPTCONN',
+    'SO_ATTACH_BPF',
+    'SO_ATTACH_FILTER',
+    'SO_ATTACH_REUSEPORT_CBPF',
     'SO_BINDTODEVICE',
     'SO_BROADCAST',
     'SO_BSDCOMPAT',
+    'SO_BSP_STATE',
+    'SO_BUSY_POLL',
+    'SO_CONDITIONAL_ACCEPT',
+    'SO_CONFIRM_NAME',
+    'SO_CONNDATA',
+    'SO_CONNDATALEN',
+    'SO_CONNECT_TIME',
+    'SO_CONNOPT',
+    'SO_CONNOPTLEN',
     'SO_DEBUG',
+    'SO_DEREGISTER_NAME',
+    'SO_DETACH_FILTER',
+    'SO_DISCDATA',
+    'SO_DISCDATALEN',
+    'SO_DISCOPT',
+    'SO_DISCOPTLEN',
     'SO_DOMAIN',
-    'SO_ERROR',
+    'SO_DONTLINGER',
     'SO_DONTROUTE',
+    'SO_ERROR',
+    'SO_EXCLUSIVEADDRUSE',
+    'SO_GETLOCALZONES',
+    'SO_GETMYZONE',
+    'SO_GETNETINFO',
+    'SO_GETZONELIST',
+    'SO_GROUP_ID',
+    'SO_GROUP_PRIORITY',
+    'SO_INCOMING_CPU',
     'SO_KEEPALIVE',
     'SO_LINGER',
+    'SO_LOOKUP_MYZONE',
+    'SO_LOOKUP_NAME',
+    'SO_LOOKUP_NETDEF_ON_ADAPTER',
+    'SO_LOOKUP_ZONES',
+    'SO_LOOKUP_ZONES_ON_ADAPTER',
     'SO_MARK',
+    'SO_MAX_MSG_SIZE',
+    'SO_MAXDG',
+    'SO_MAXPATHDG',
     'SO_OOBINLINE',
+    'SO_OPENTYPE',
+    'SO_PAP_GET_SERVER_STATUS',
+    'SO_PAP_PRIME_READ',
+    'SO_PAP_SET_SERVER_STATUS',
     'SO_PASSCRED',
+    'SO_PASSSEC',
+    'SO_PAUSE_ACCEPT',
+    'SO_PEEK_OFF',
     'SO_PEERCRED',
+    'SO_PORT_SCALABILITY',
     'SO_PRIORITY',
     'SO_PROTOCOL',
+    'SO_PROTOCOL_INFO',
+    'SO_PROTOCOL_INFOA',
+    'SO_PROTOCOL_INFOW',
+    'SO_RANDOMIZE_PORT',
     'SO_RCVBUF',
     'SO_RCVBUFFORCE',
     'SO_RCVLOWAT',
-    'SO_SNDLOWAT',
     'SO_RCVTIMEO',
-    'SO_SNDTIMEO',
+    'SO_REGISTER_NAME',
+    'SO_REMOVE_NAME',
+    'SO_REUSE_MULTICASTPORT',
+    'SO_REUSE_UNICASTPORT',
     'SO_REUSEADDR',
+    'SO_REUSEPORT',
+    'SO_RXQ_OVFL',
     'SO_SNDBUF',
     'SO_SNDBUFFORCE',
+    'SO_SNDLOWAT',
+    'SO_SNDTIMEO',
     'SO_TIMESTAMP',
-    'SO_TYPE'
+    'SO_TYPE',
+    'SO_UPDATE_ACCEPT_CONTEXT',
+    'SO_UPDATE_CONNECT_CONTEXT',
+    'SO_USELOOPBACK',
+    'TCP_BSDURGENT',
+    'TCP_CONGESTION',
+    'TCP_CORK',
+    'TCP_DEFER_ACCEPT',
+    'TCP_EXPEDITED_1122',
+    'TCP_FASTOPEN',
+    'TCP_INFO',
+    'TCP_KEEPCNT',
+    'TCP_KEEPIDLE',
+    'TCP_KEEPINTVL',
+    'TCP_LINGER2',
+    'TCP_MAXRT',
+    'TCP_MAXSEG',
+    'TCP_NODELAY',
+    'TCP_QUICKACK',
+    'TCP_SYNCNT',
+    'TCP_TIMESTAMPS',
+    'TCP_USER_TIMEOUT',
+    'TCP_WINDOW_CLAMP',
 ]
 
 PDF_DID = [
diff --git a/stix2validator/v21/musts.py b/stix2validator/v21/musts.py
index 9c71fa9..776adc4 100644
--- a/stix2validator/v21/musts.py
+++ b/stix2validator/v21/musts.py
@@ -408,6 +408,9 @@ def patterns(instance, options):
     if instance['type'] != 'indicator' or 'pattern' not in instance:
         return
 
+    if instance['pattern_type'] != 'stix':
+        return
+
     pattern = instance['pattern']
     if not isinstance(pattern, string_types):
         return  # This error already caught by schemas
diff --git a/stix2validator/v21/shoulds.py b/stix2validator/v21/shoulds.py
index 1b442ff..78f19ec 100644
--- a/stix2validator/v21/shoulds.py
+++ b/stix2validator/v21/shoulds.py
@@ -348,6 +348,11 @@ def vocab_region(instance):
                        'region')
 
 
+def vocab_pattern_type(instance):
+    return check_vocab(instance, "INDICATOR_PATTERN",
+                       'indicator-pattern-types')
+
+
 def vocab_marking_definition(instance):
     """Ensure that the `definition_type` property of `marking-definition`
     objects is one of the values in the STIX 2.0 specification.
@@ -948,7 +953,7 @@ def socket_options(instance):
             if opt not in enums.SOCKET_OPTIONS:
                 yield JSONError("The 'options' property of object '%s' "
                                 "contains a key ('%s') that is not a valid"
-                                " socket option (SO_*)."
+                                " socket option (SO|ICMP|ICMP6|IP|IPV6|MCAST|TCP|IRLMP)_*."
                                 % (instance['id'], opt), instance['id'], 'socket-options')
 
 
@@ -1278,6 +1283,7 @@ CHECKS = {
         vocab_indicator_types,
         vocab_industry_sector,
         vocab_malware_types,
+        vocab_pattern_type,
         vocab_report_types,
         vocab_threat_actor_types,
         vocab_threat_actor_role,
@@ -1342,6 +1348,7 @@ CHECKS = {
         vocab_indicator_types,
         vocab_industry_sector,
         vocab_malware_types,
+        vocab_pattern_type,
         vocab_report_types,
         vocab_threat_actor_types,
         vocab_threat_actor_role,
@@ -1376,6 +1383,7 @@ CHECKS = {
         vocab_indicator_types,
         vocab_industry_sector,
         vocab_malware_types,
+        vocab_pattern_type,
         vocab_report_types,
         vocab_threat_actor_types,
         vocab_threat_actor_role,
@@ -1395,6 +1403,7 @@ CHECKS = {
     'malware-capabilities': vocab_malware_capabilities,
     'processor-architecture': vocab_processor_architecture,
     'identity-class': vocab_identity_class,
+    'indicator-pattern-types': vocab_pattern_type,
     'indicator-types': vocab_indicator_types,
     'industry-sector': vocab_industry_sector,
     'malware-types': vocab_malware_types,
@@ -1492,6 +1501,8 @@ def list_shoulds(options):
                         validator_list.append(CHECKS['attack-resource-level'])
                     if 'identity-class' not in options.disabled:
                         validator_list.append(CHECKS['identity-class'])
+                    if 'indicator-pattern-types' not in options.disabled:
+                        validator_list.append(CHECKS['indicator-pattern-types'])
                     if 'indicator-types' not in options.disabled:
                         validator_list.append(CHECKS['indicator-types'])
                     if 'industry-sector' not in options.disabled:
diff --git a/tox.ini b/tox.ini
index 2989c83..684f6b8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27,py34,py35,py36,py37,style,isort-check,packaging
+envlist = py27,py34,py35,py36,py37,py38,style,isort-check,packaging
 
 [testenv]
 deps =


Test patch:
diff --git a/stix2validator/test/v21/indicator_tests.py b/stix2validator/test/v21/indicator_tests.py
index 778827c..158788e 100644
--- a/stix2validator/test/v21/indicator_tests.py
+++ b/stix2validator/test/v21/indicator_tests.py
@@ -240,3 +240,29 @@ class IndicatorTestCases(ValidatorTest):
         self.assertFalseWithOptions(indicator)
 
         self.check_ignore(indicator, 'indicator-properties')
+
+    def test_indicator_different_pattern_type_does_not_get_validated(self):
+        pattern = ("alert tcp any any <> any 80 (msg:\"SHA256 Alert\";"
+                   " protected_content:\"56D6F32151AD8474F40D7B939C2161EE2BBF10023F4AF1DBB3E13260EBDC6342\";"
+                   " hash:sha256; offset:0; length:4;)")
+        indicator = copy.deepcopy(self.valid_indicator)
+        indicator["pattern"] = pattern
+        indicator["pattern_type"] = "snort"
+        indicator["pattern_version"] = "2.9.15"
+
+        results = validate_parsed_json(indicator, self.options)
+        self.assertEqual(results.is_valid, True)
+
+    def test_indicator_different_pattern_type_not_in_enum(self):
+        pattern = ("signature example-signature {"
+                   "ip-proto == tcp"
+                   "dst-port == 80"
+                   "payload /^Some expression/"
+                   "}")
+        indicator = copy.deepcopy(self.valid_indicator)
+        indicator["pattern"] = pattern
+        indicator["pattern_type"] = "zeek"
+        indicator["pattern_version"] = "3.0.1"
+
+        self.assertFalseWithOptions(indicator)
+        self.check_ignore(indicator, 'indicator-pattern-types')