示例#1
0
 def setUp(self):
     fn = os.path.join('schema', 'exp.jadn')        # Load experimental OpenC2 schema
     schema = jadn_load(fn)
     sa = jadn_analyze(schema)
     if sa['undefined']:
         print('Warning - undefined:', sa['undefined'])
     self.tc = Codec(schema, verbose_rec=True, verbose_str=True)
示例#2
0
 def setUp(self):
     fn = os.path.join('schema', 'oc2ls-csdpr02-slpf_merged.jadn')
     schema = jadn_load(fn)
     sa = jadn_analyze(schema)
     if sa['undefined']:
         print('Warning - undefined:', sa['undefined'])
     self.tc = Codec(schema, verbose_rec=True, verbose_str=True)
class Relax2(unittest.TestCase):
    def setUp(self):
        schema = jadn_load(os.path.join("schema", "relax2.jadn"))
        self.tc = Codec(schema)

    def test1_attribute_syntax(self):
        msg_api = [{
            "a": {
                "type": "name",
                "value": "John Smith"
            },
            "b": {
                "type": "email",
                "value": "*****@*****.**"
            }
        }, {
            "a": {
                "type": "name",
                "value": "Fred Bloggs"
            },
            "b": {
                "type": "email",
                "value": "*****@*****.**"
            }
        }]
        msg_min = [["John Smith", "*****@*****.**"],
                   ["Fred Bloggs", "*****@*****.**"]]

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("addressBook", msg_api), msg_api)
        self.assertEqual(self.tc.decode("addressBook", msg_api), msg_api)
        self.tc.set_mode(False, False)  # Minified (list/tag)
        self.assertEqual(self.tc.encode("addressBook", msg_api), msg_min)
        self.assertEqual(self.tc.decode("addressBook", msg_min), msg_api)
示例#4
0
class BasicTypes(unittest.TestCase):
    def setUp(self):
        jadn_check(schema_person)
        jadn_analyze(schema_person)
        self.c = Codec(schema_person, "True",
                       "True")  # Verbose encoding mode (dict/name)

    def test_person(self):
        p1 = {"name": "Jon Public", "id": 196432}

        p2 = {"name": "Jon Public", "id": 196432, "email": "*****@*****.**"}

        p3 = {
            "name":
            "Jon Public",
            "id":
            196432,
            "phone": [{
                "number": "201-555-1234"
            }, {
                "number": "201-555-5678",
                "type": "WORK"
            }]
        }

        p4bad = {  # Missing required id
            "name": "Jon Public"
        }

        p5bad = {  # Bad phone type
            "name": "Jon Public",
            "id": 196432,
            "phone": [{
                "number": "201-555-1234",
                "type": "CELL"
            }]
        }

        self.assertEqual(self.c.encode("Person", p1), p1)
        self.assertEqual(self.c.encode("Person", p2), p2)
        self.assertEqual(self.c.encode("Person", p3), p3)
        with self.assertRaises(ValueError):
            self.assertEqual(self.c.encode("Person", p4bad), p4bad)
        with self.assertRaises(ValueError):
            self.assertEqual(self.c.encode("Person", p5bad), p5bad)
示例#5
0
class Experimental_IPv6_Net(unittest.TestCase):

    def setUp(self):
        fn = os.path.join('schema', 'exp.jadn')        # Load experimental OpenC2 schema
        schema = jadn_load(fn)
        sa = jadn_analyze(schema)
        if sa['undefined']:
            print('Warning - undefined:', sa['undefined'])
        self.tc = Codec(schema, verbose_rec=True, verbose_str=True)

    ipv6_net_api = {           # API IPv4 net.
        'ipv6_net': [b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH', 64]}

    ipv6_net_api_bad1 = {       # Negative
        'ipv6_net': [b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH', -3]}

    ipv6_net_api_bad2 = {       # Too large
        'ipv6_net': [b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH', 142]}

    ipv6_net_ser = {            # IPv4 net serialized in type-specific string (dotted decimal) format
        'ipv6_net': '2001:db8:85a3:8d3:1319:8a2e:370:7348/64'}

    ipv6_net_ser_bad1 = {       # Leading 0
        'ipv6_net': '2001:db8:85a3:8d3:1319:8a2e:370:7348/064'}

    ipv6_net_ser_bad2 = {       # Negative
        'ipv6_net': '2001:db8:85a3:8d3:1319:8a2e:370:7348/-3'}

    ipv6_net_ser_bad3 = {       # Too large
        'ipv6_net': '2001:db8:85a3:8d3:1319:8a2e:370:7348/142'}

    def test_ipv6_net(self):
        self.assertEqual(self.tc.encode('Target', self.ipv6_net_api), self.ipv6_net_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv6_net_ser), self.ipv6_net_api)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv6_net_api_bad1)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv6_net_api_bad2)
#        with self.assertRaises(ValueError):
#            self.tc.decode('Target', self.ipv6_net_ser_bad1)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv6_net_ser_bad2)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv6_net_ser_bad3)
示例#6
0
class Experimental_IPv4_Net(unittest.TestCase):

    def setUp(self):
        fn = os.path.join('schema', 'exp.jadn')        # Load experimental OpenC2 schema
        schema = jadn_load(fn)
        sa = jadn_analyze(schema)
        if sa['undefined']:
            print('Warning - undefined:', sa['undefined'])
        self.tc = Codec(schema, verbose_rec=True, verbose_str=True)

    ipv4_net_api = {           # API IPv4 net.
        'ipv4_net': [b'\xc0\xa8\x00\xfe', 24]}

    ipv4_net_api_bad1 = {       # Negative
        'ipv4_net': [b'\xc0\xa8\x00\xfe', -3]}

    ipv4_net_api_bad2 = {       # Too large
        'ipv4_net': [b'\xc0\xa8\x00\xfe', 42]}

    ipv4_net_ser = {            # IPv4 net serialized in type-specific string (dotted decimal) format
        'ipv4_net': '192.168.0.254/24'}

    ipv4_net_ser_bad1 = {       # Leading 0
        'ipv4_net': '192.168.0.254/024'}

    ipv4_net_ser_bad2 = {       # Negative
        'ipv4_net': '192.168.0.254/-3'}

    ipv4_net_ser_bad3 = {       # Too large
        'ipv4_net': '192.168.0.254/42'}

    def test_ipv4_net(self):
        self.assertEqual(self.tc.encode('Target', self.ipv4_net_api), self.ipv4_net_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv4_net_ser), self.ipv4_net_api)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv4_net_api_bad1)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv4_net_api_bad2)
#        with self.assertRaises(ValueError):
#            self.tc.decode('Target', self.ipv4_net_ser_bad1)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_net_ser_bad2)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_net_ser_bad3)
class OpenC2(unittest.TestCase):
    def setUp(self):
        schema = jadn_load(os.path.join("schema", "openc2.jadn"))
        self.tc = Codec(schema, True, True)

    def test01_high_level(self):
        cmd_api = {
            "action": "deny",
            "target": {
                "ip_connection": {
                    "src_addr": "1.2.3.4",
                    "src_port": 21,
                    "layer4_protocol": "tcp"
                }
            }
        }

        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        print(json.dumps(cmd_api, indent=2))
示例#8
0
class Compound(
        unittest.TestCase
):  # TODO: arrayOf(rec,map,array,arrayof,choice), array(), map(), rec()
    def setUp(self):
        jadn_check(schema_compound)
        self.tc = Codec(schema_compound)

    C4a = {"rec": {"a": 1, "b": "c"}}
    C4m = {"10": [1, "c"]}

    def test_choice_rec_verbose(self):
        self.tc.set_mode(True, True)
        self.assertEqual(self.tc.decode("t_choice", self.C4a), self.C4a)
        self.assertEqual(self.tc.encode("t_choice", self.C4a), self.C4a)

    def test_choice_rec_min(self):
        self.tc.set_mode(False, False)
        self.assertEqual(self.tc.decode("t_choice", self.C4m), self.C4a)
        self.assertEqual(self.tc.encode("t_choice", self.C4a), self.C4m)
 def setUp(self):
     schema = jadn_load(os.path.join("schema", "openc2.jadn"))
     self.tc = Codec(schema, True, True)
示例#10
0
class SLPF(unittest.TestCase):

    def setUp(self):
        fn = os.path.join('schema', 'oc2ls-csdpr02-slpf_merged.jadn')
        schema = jadn_load(fn)
        sa = jadn_analyze(schema)
        if sa['undefined']:
            print('Warning - undefined:', sa['undefined'])
        self.tc = Codec(schema, verbose_rec=True, verbose_str=True)

    mdeny1c = {
      'action': 'deny',
      'target': {
        'ip_connection': {
          'protocol': 'tcp',
          'src_addr': b'\x01\x02\x03\x04',
          'src_port': 10996,
          'dst_addr': b'\xc6\x02\x03\x04',
          'dst_port': 80
        }
      },
      'args': {
        'start_time': 1534775460000,
        'duration': 500,
        'response_requested': 'ack',
        'slpf': {
          'drop_process': 'none'
        }
      },
      'actuator': {
        'slpf': {
          'asset_id': '30'
        }
      }
    }

    mdeny1c_s = {
      'action': 'deny',
      'target': {
        'ip_connection': {
          'protocol': 'tcp',
          'src_addr': 'AQIDBA',
          'src_port': 10996,
          'dst_addr': 'xgIDBA',
          'dst_port': 80
        }
      },
      'args': {
        'start_time': 1534775460000,
        'duration': 500,
        'response_requested': 'ack',
        'slpf': {
          'drop_process': 'none'
        }
      },
      'actuator': {
        'slpf': {
          'asset_id': '30'
        }
      }
    }

    mdeny1r = {
      'status': 200
    }

    mdeny2c = {
      'action': 'deny',
      'target': {
        'ip_connection': {
          'protocol': 'tcp',
          'src_port': 21
        }
      },
      'args': {
        'slpf': {
          'drop_process': 'false_ack'
        }
      },
      'actuator': {
        'slpf': {}
      }
    }

    mdeny2r1 = {'status':200}
    mdeny2r2 = {
      'status': 400,
      'status_text': 'Validation Error: Target: ip_conection'
    }
    mdeny2r3 = {
      'status': 501
    }

    mdeny3c = {
      'action': 'deny',
      'target': {
        'ip_addr': b'\x01\x02\x03\x04'
      },
      'args': {
        'response_requested': 'none',
        'slpf': {
          'direction': 'ingress'
        }
      },
      'actuator': {
        'slpf': {
          'named_group': 'perimeter'
        }
      }
    }

    mdeny3c_s = {
      'action': 'deny',
      'target': {
        'ip_addr': 'AQIDBA'
      },
      'args': {
        'response_requested': 'none',
        'slpf': {
          'direction': 'ingress'
        }
      },
      'actuator': {
        'slpf': {
          'named_group': 'perimeter'
        }
      }
    }

    mdeny4c = {
      'action': 'allow',
      'target': {
        'ip_connection': {
          'protocol': 'tcp',
          'dst_addr': b'\xc6\x33\x64\x11',
          'src_port': 21
        }
      },
      'actuator': {
        'slpf': {}
      }
    }


    mdeny4c_s = {
      'action': 'allow',
      'target': {
        'ip_connection': {
          'protocol': 'tcp',
          'dst_addr': 'xjNkEQ',
          'src_port': 21
        }
      },
      'actuator': {
        'slpf': {}
      }
    }


    mdeny4r = {
      'status': 200,
      'slpf': {
        'rule_number': 1234
      }
    }

    mdelete1c = {
      'action': 'delete',
      'target': {
        'slpf': {
          'rule_number': 1234
        }
      },
      'args': {
        'response_requested': 'complete'
      },
      'actuator': {
        'slpf': {}
      }
    }

    mupdate1c = {
      'action': 'update',
      'target': {
        'file': {
          'path': '\\\\someshared-drive\\somedirectory\\configurations',
          'name': 'firewallconfiguration.txt'
        }
      },
      'actuator': {
        'slpf': {
          'named_group': 'network'
        }
      }
    }

    mupdate1r1 = {'status':200}
    mupdate1r2 = {
      'status': 501,
      'status_text': 'Update-File Not Implemented'
    }
    mupdate1r3 = {
      'status': 500,
      'status_text': 'Server error, Cannot access file'
    }

    mquery1c = {
      'action': 'query',
      'target': {
        'features': []
      }
    }

    mquery1r = {'status':200}

    mquery2c = {
      'action': 'query',
      'target': {
        'features': ['versions']
      }
    }

    mquery2r = {
      'status': 200,
      'versions': ['1.3']
    }

    mquery3c = {
      'action': 'query',
      'target': {
        'features': ['versions', 'profiles']
      }
    }

    mquery3r = {
      'status': 200,
      'versions': ['1.3'],
      'profiles': [
        'oasis-open.org/openc2/v1.0/ap-slpf',
        'example.com/openc2/products/iot-toaster'
      ]
    }

    mquery4c = {
      'action': 'query',
      'target': {
        'features': ['pairs']
      }
    }

    mquery4r = {
        'status': 200,
        'schema': {
            'meta': {
                'module': 'oasis-open.org/openc2/v1.0/openc2-lang',
                'patch': 'wd08-slpf-VendorX',
                'title': 'OpenC2 Language Objects',
                'description': 'OpenC2 Language supported by Vendor X SLPF.',
                'exports': ['OpenC2-Command', 'OpenC2-Response']
            },
            'types': [
                ['OpenC2-Command', 'Record', [], '', [
                    [1, 'action', 'Action', [], ''],
                    [2, 'target', 'Target', [], ''],
                    [3, 'actuator', 'Actuator', ['[0'], ''],
                    [4, 'args', 'Args', ['[0'], ''],
                    [5, 'id', 'Command-ID', ['[0'], '']]
                 ],
                ['Action', 'Enumerated', [], '', [
                    [3, 'query', ''],
                    [6, 'deny', ''],
                    [8, 'allow', ''],
                    [16, 'update', ''],
                    [20, 'delete', '']]
                 ],
                ['Target', 'Choice', [], '', [
                    [10, 'file', 'File', [], ''],
                    [11, 'ip_addr', 'IP-Addr', [], ''],
                    [15, 'ip_connection', 'IP-Connection', [], ''],
                    [16, 'openc2', 'OpenC2', [], ''],
                    [1024, 'slpf', 'slpf:Target', [], '']]
                 ],
                ['Actuator', 'Choice', [], '', [
                    [1024, 'slpf', 'slpf:Specifiers', [], '']]
                 ],
                ['Args', 'Map', [], '', [
                    [1, 'start_time', 'Date-Time', ['[0'], ''],
                    [2, 'stop_time', 'Date-Time', ['[0'], ''],
                    [3, 'duration', 'Duration', ['[0'], ''],
                    [4, 'response_requested', 'Response-Type', ['[0'], ''],
                    [1024, 'slpf', 'slpf:Args', ['[0'], '']]
                 ],
                ['OpenC2-Response', 'Record', [], '', [
                    [1, 'status', 'Status-Code', [], ''],
                    [2, 'status_text', 'String', ['[0'], ''],
                    [3, '*', 'Results', ['[0'], ''],
                    [4, 'id', 'Command-ID', ['[0'], ''],
                    [5, 'id_ref', 'Command-ID', ['[0'], ''],
                    [6, 'actuator_id', 'String', ['[0'], '']]
                 ],
                ['Status-Code', 'Enumerated', ['='], '', [
                    [102, 'Processing', ''],
                    [200, 'OK', ''],
                    [301, 'Moved Permanently', ''],
                    [400, 'Bad Request', ''],
                    [401, 'Unauthorized', ''],
                    [403, 'Forbidden', ''],
                    [500, 'Server Error', ''],
                    [501, 'Not Implemented', '']]
                 ],
                ['File', 'Map', [], '', [
                    [1, 'name', 'String', ['[0'], ''],
                    [2, 'path', 'String', ['[0'], ''],
                    [3, 'hashes', 'Hashes', ['[0'], '']]
                 ],
                ['IP-Addr', 'Binary', [], ''],
                ['IP-Connection', 'Record', [], '', [
                    [1, 'src_addr', 'IP-Addr', ['[0'], ''],
                    [2, 'src_port', 'Port', ['[0'], ''],
                    [3, 'dst_addr', 'IP-Addr', ['[0'], ''],
                    [4, 'dst_port', 'Port', ['[0'], ''],
                    [5, 'protocol', 'L4-Protocol', ['[0'], '']]
                 ],
                ['OpenC2', 'ArrayOf', ['*Query-Item', '[0', ']3'], ''],
                ['Command-ID', 'String', [], ''],
                ['Date-Time', 'Integer', [], ''],
                ['Duration', 'Integer', [], ''],
                ['Hashes', 'Map', [], '', [
                    [1, 'md5', 'Binary', ['[0'], ''],
                    [4, 'sha1', 'Binary', ['[0'], ''],
                    [6, 'sha256', 'Binary', ['[0'], '']]
                 ],
                ['L4-Protocol', 'Enumerated', [], '', [
                    [1, 'icmp', ''],
                    [6, 'tcp', ''],
                    [17, 'udp', ''],
                    [132, 'sctp', '']]
                 ],
                ['Port', 'String', ['@port'], ''],
                ['Query-Item', 'Enumerated', [], '', [
                    [1, 'versions', ''],
                    [2, 'profiles', ''],
                    [3, 'schema', ''],
                    [4, 'pairs', '']]
                 ],
                ['Response-Type', 'Enumerated', [], '', [
                    [0, 'none', ''],
                    [1, 'ack', ''],
                    [2, 'status', ''],
                    [3, 'complete', '']]
                 ],
                ['Version', 'String', [], ''],
                ['Results', 'Map', [], '', [
                    [4, 'versions', 'Version', ['[0', ']0'], ''],
                    [5, 'profiles', 'jadn:Uname', ['[0', ']0'], ''],
                    [6, 'schema', 'jadn:Schema', ['[0', ']0'], ''],
                    [7, 'pairs', 'ActionTargets', ['[0', ']0'], ''],
                    [1024, 'slpf', 'slpf:Results', ['[0', ']0'], '']]
                 ],
                ['ActionTargets', 'Array', [], '', [
                    [1, 'action', 'Action', [], ''],
                    [2, 'targets', 'Target.*', [']0'], '']]
                 ],

                ['slpf:Target', 'Choice', [], '', [
                    [1, 'rule_number', 'slpf:Rule-ID', [], '']]
                 ],
                ['slpf:Args', 'Map', [], '', [
                    [1, 'drop_process', 'slpf:Drop-Process', ['[0'], ''],
                    [2, 'running', 'Boolean', ['[0'], ''],
                    [3, 'direction', 'slpf:Direction', ['[0'], ''],
                    [4, 'insert_rule', 'slpf:Rule-ID', ['[0'], '']]
                 ],
                ['slpf:Drop-Process', 'Enumerated', [], '', [
                    [1, 'none', ''],
                    [2, 'reject', ''],
                    [3, 'false_ack', '']]
                 ],
                ['slpf:Direction', 'Enumerated', [], '', [
                    [1, 'ingress', ''],
                    [2, 'egress', '']]
                 ],
                ['slpf:Rule-ID', 'Integer', [], ''],
                ['slpf:Specifiers', 'Map', [], '', [
                    [1, 'hostname', 'String', ['[0'], ''],
                    [2, 'named_group', 'String', ['[0'], ''],
                    [3, 'asset_id', 'String', ['[0'], ''],
                    [4, 'asset_tuple', 'String', ['[0', ']10'], '']]
                 ],
                ['slpf:Results', 'Map', [], '', [
                    [1, 'rule_number', 'slpf:Rule-ID', ['[0'], '']]
                 ],

                ['jadn:Schema', 'Record', [], '', [
                    [1, 'meta', 'jadn:Meta', [], ''],
                    [2, 'types', 'jadn:Type', [']0'], '']]
                 ],
                ['jadn:Meta', 'Map', [], '', [
                    [1, 'module', 'jadn:Uname', [], ''],
                    [2, 'patch', 'String', ['[0'], ''],
                    [3, 'title', 'String', ['[0'], ''],
                    [4, 'description', 'String', ['[0'], ''],
                    [5, 'imports', 'jadn:Import', ['[0', ']0'], ''],
                    [6, 'exports', 'jadn:Identifier', ['[0', ']0'], ''],
                    [7, 'bounds', 'jadn:Bounds', ['[0'], '']]
                 ],
                ['jadn:Import', 'Array', [], '', [
                    [1, 'nsid', 'jadn:Nsid', [], ''],
                    [2, 'uname', 'jadn:Uname', [], '']]
                 ],
                ['jadn:Bounds', 'Array', [], '', [
                    [1, 'max_msg', 'Integer', [], ''],
                    [2, 'max_str', 'Integer', [], ''],
                    [3, 'max_bin', 'Integer', [], ''],
                    [4, 'max_fields', 'Integer', [], '']]
                 ],
                ['jadn:Type', 'Array', [], '', [
                    [1, 'tname', 'jadn:Identifier', [], ''],
                    [2, 'btype', 'Enumerated', ['*jadn:JADN-Type'], ''],
                    [3, 'opts', 'jadn:Options', [], ''],
                    [4, 'desc', 'String', [], ''],
                    [5, 'fields', 'jadn:JADN-Type', ['&2', '[0', ']0'], '']]
                 ],
                ['jadn:JADN-Type', 'Choice', [], '', [
                    [1, 'Binary', 'Null', [], ''],
                    [2, 'Boolean', 'Null', [], ''],
                    [3, 'Integer', 'Null', [], ''],
                    [4, 'Number', 'Null', [], ''],
                    [5, 'Null', 'Null', [], ''],
                    [6, 'String', 'Null', [], ''],
                    [7, 'Array', 'jadn:FullField', [], ''],
                    [8, 'ArrayOf', 'Null', [], ''],
                    [9, 'Choice', 'jadn:FullField', [], ''],
                    [10, 'Enumerated', 'jadn:EnumField', [], ''],
                    [11, 'Map', 'jadn:FullField', [], ''],
                    [12, 'Record', 'jadn:FullField', [], '']]
                 ],
                ['jadn:EnumField', 'Array', [], '', [
                    [1, '', 'Integer', [], ''],
                    [2, '', 'String', [], ''],
                    [3, '', 'String', [], '']]
                 ],
                ['jadn:FullField', 'Array', [], '', [
                    [1, '', 'Integer', [], ''],
                    [2, '', 'jadn:Identifier', [], ''],
                    [3, '', 'jadn:Identifier', [], ''],
                    [4, '', 'jadn:Options', [], ''],
                    [5, '', 'String', [], '']]
                 ],
                ['jadn:Identifier', 'String', ['$^[a-zA-Z][\\w-]*$', '[0', ']32'], ''],
                ['jadn:Nsid', 'String', ['$^[a-zA-Z][\\w-]*$', '[1', ']8'], ''],
                ['jadn:Uname', 'String', ['[1', ']100'], ''],
                ['jadn:Options', 'ArrayOf', ['*jadn:Option', '[0', ']10'], ''],
                ['jadn:Option', 'String', ['[1', ']100'], '']
            ]
        }
    }

    def test_deny1c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mdeny1c), self.mdeny1c_s)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mdeny1c_s), self.mdeny1c)

    def test_deny1r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mdeny1r), self.mdeny1r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mdeny1r), self.mdeny1r)

    def test_deny2c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mdeny2c), self.mdeny2c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mdeny2c), self.mdeny2c)

    def test_deny2r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mdeny2r1), self.mdeny2r1)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mdeny2r1), self.mdeny2r1)
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mdeny2r2), self.mdeny2r2)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mdeny2r2), self.mdeny2r2)
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mdeny2r3), self.mdeny2r3)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mdeny2r3), self.mdeny2r3)

    def test_deny3c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mdeny3c), self.mdeny3c_s)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mdeny3c_s), self.mdeny3c)

    def test_deny4c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mdeny4c), self.mdeny4c_s)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mdeny4c_s), self.mdeny4c)

    def test_deny4r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mdeny4r), self.mdeny4r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mdeny4r), self.mdeny4r)

    def test_delete1c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mdelete1c), self.mdelete1c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mdelete1c), self.mdelete1c)

    def test_update1c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mupdate1c), self.mupdate1c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mupdate1c), self.mupdate1c)

    def test_update1r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mupdate1r1), self.mupdate1r1)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mupdate1r1), self.mupdate1r1)
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mupdate1r2), self.mupdate1r2)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mupdate1r2), self.mupdate1r2)
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mupdate1r3), self.mupdate1r3)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mupdate1r3), self.mupdate1r3)

    def test_query1c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mquery1c), self.mquery1c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mquery1c), self.mquery1c)

    def test_query1r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mquery1r), self.mquery1r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mquery1r), self.mquery1r)

    def test_query2c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mquery2c), self.mquery2c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mquery2c), self.mquery2c)

    def test_query2r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mquery2r), self.mquery2r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mquery2r), self.mquery2r)

    def test_query3c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mquery3c), self.mquery3c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mquery3c), self.mquery3c)

    def test_query3r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mquery3r), self.mquery3r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mquery3r), self.mquery3r)

    def test_query4c(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mquery4c), self.mquery4c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mquery4c), self.mquery4c)

    def test_query4r(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mquery4r), self.mquery4r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mquery4r), self.mquery4r)
示例#11
0
class Language(unittest.TestCase):

    def setUp(self):
        fn = os.path.join('schema', 'oc2ls-csdpr02_merged.jadn')
        schema = jadn_load(fn)
        sa = jadn_analyze(schema)
        if sa['undefined']:
            print('Warning - undefined:', sa['undefined'])
        self.tc = Codec(schema, verbose_rec=True, verbose_str=True)

    mredirect = {'action': 'redirect', 'target': {'url': 'http://evil.com'}, 'args': {''}}

    mq1 = {'action': 'query', 'target': {'features': ['versions']}}
    mq2 = {'action': 'query', 'target': {'features': ['profiles']}}

    def test_query_oc2(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mq1), self.mq1)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mq1), self.mq1)
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mq2), self.mq2)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mq2), self.mq2)
#        with self.assertRaises(TypeError):
#            self.tc.encode('OpenC2-Command', self.mq_bad1)
#        with self.assertRaises(TypeError):
#            self.tc.decode('OpenC2-Command', self.mq_bad1)

    mr1 = {'status': 200}
    mr2 = {'status': 200,
           'status_text': 'The request has succeeded',
           'versions': ['foo']
        }

    def test_response_oc2(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mr1), self.mr1)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mr1), self.mr1)
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mr2), self.mr2)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mr2), self.mr2)

    mex2c = {
        'action': 'query',
        'target': {
            'properties': ['battery_percentage']
        }
    }

    mex2r = {
        'kvps': [['battery_percentage', '0.577216']]
    }

    def test_properties_cmd(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mex2c), self.mex2c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mex2c), self.mex2c)

    def test_properties_rsp(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mex2r), self.mex2r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mex2r), self.mex2r)

    mex3c = {
        'action': 'query',
        'target': {
            'features': ['versions', 'profiles']
        }
    }

    mex3r = {
        "status_text": 'ACME Corp Stateless Packet Filter Appliance',
        'versions': ['1.0'],
        'profiles': [
            'oasis-open.org/openc2/v1.0/ap-slpf'
        ]
    }

    def test_features_cmd(self):
        self.assertEqual(self.tc.encode('OpenC2-Command', self.mex3c), self.mex3c)
        self.assertEqual(self.tc.decode('OpenC2-Command', self.mex3c), self.mex3c)

    def test_features_rsp(self):
        self.assertEqual(self.tc.encode('OpenC2-Response', self.mex3r), self.mex3r)
        self.assertEqual(self.tc.decode('OpenC2-Response', self.mex3r), self.mex3r)
示例#12
0
from libs.codec.codec import Codec
from libs.codec.codec_utils import flatten
from libs.codec.jadn import jadn_load

# OpenC2 producer application:

command1 = {  # Python literals use either single or double quotes - no difference in API object
    "action": "mitigate",
    'target': {
        "domain_name": 'cdn.badco.org'
    }
}

schema = jadn_load(os.path.join(
    "schema", "openc2.jadn"))  # Load and validate the OpenC2 schema
codec = Codec(schema, verbose_rec=True, verbose_str=True
              )  # Create an OpenC2 encoder/decoder (JSON-Verbose encoding)
message1 = codec.encode("OpenC2Command",
                        command1)  # Validate and encode the command
print("Command to be sent (API)         =", command1)
print("Sent Message (JSON-v string)     =",
      json.dumps(message1))  # Single quotes are invalid in JSON

# OpenC2 consumer application:

message2 = '[32,{"7":"cdn.badco.org"}]'  # Received OpenC2 command in JSON-minified format
codec.set_mode(verbose_rec=False,
               verbose_str=False)  # Tell codec to use JSON-minified encoding
command2 = codec.decode(
    "OpenC2Command", json.loads(message2))  # Validate and decode the command
print("Received Message (JSON-m string) =", message2)
print("Decoded Command (API)            =", command2)
示例#13
0
class OpenC2(unittest.TestCase):
    def _write_examples(self, name, cmds):
        """
        Create example JSON files as a side effect of running unit tests
        """

        if True:  # Set to False to not write example files
            for n, encoding in enumerate(["", "_flat", "_concise", "_min"]):
                if cmds[n] is not None:
                    with open(
                            os.path.join("examples",
                                         name + encoding + ".json"), "w") as f:
                        f.write(json.dumps(cmds[n]))

    def setUp(self):
        schema = jadn_load(os.path.join("schema", "openc2.jadn"))
        self.tc = Codec(schema)

    def test01_mitigate_domain(self):
        cmd_api = {
            "action": "mitigate",
            "target": {
                "domain_name": "cdn.badco.org"
            }
        }
        cmd_flat = {
            "action": "mitigate",
            "target.domain_name": "cdn.badco.org"
        }
        cmd_noname = {"1": 32, "2": {"7": "cdn.badco.org"}}
        cmd_concise = ["mitigate", {"domain_name": "cdn.badco.org"}]
        cmd_min = [32, {"7": "cdn.badco.org"}]

        # Minified (list/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_min)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_min), cmd_api)
        self.tc.set_mode(False, True)  # Concise (list/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_concise)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_concise), cmd_api)
        self.tc.set_mode(True, False)  # unused (dict/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_noname)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_noname), cmd_api)
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(flatten(cmd_api), cmd_flat)
        self.assertEqual(fluff(cmd_flat), cmd_api)
        self._write_examples("t01_mitigate_domain",
                             [cmd_api, cmd_flat, cmd_concise, cmd_min])

    def test02_query_actions(self):
        cmd_api = {"action": "query", "target": {"openc2": {"actions": ""}}}
        rsp_api = {
            "status": "OK",
            "results": {
                "strings": [
                    "query", "report", "notify", "start", "stop", "set",
                    "delete", "update", "investigate", "mitigate", "remediate"
                ]
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t02_query_actions", [cmd_api, None, None, None])
        self.assertEqual(self.tc.encode("OpenC2Response", rsp_api), rsp_api)
        self.assertEqual(self.tc.decode("OpenC2Response", rsp_api), rsp_api)
        self._write_examples("t02_query_actions_response",
                             [rsp_api, None, None, None])

    def test02_query_schema(self):
        cmd_api = {"action": "query", "target": {"openc2": {"schema": ""}}}
        schema = {  # JSON does not allow line breaks within strings for readability.  So encode struct into string.
            "meta": {
                "module": "openc2"
            },
            "types": [[
                "OpenC2Command", "Record", [], "",
                [[1, "action", "Action", [], ""],
                 [2, "target", "Target", [], ""],
                 [3, "actuator", "Actuator", ["?"], ""],
                 [4, "modifiers", "Modifiers", ["?"], ""]]
            ]]
        }
        rsp_api = {"status": "OK", "results": {"string": json.dumps(schema)}}

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t02_query_schema", [cmd_api, None, None, None])
        self.assertEqual(self.tc.encode("OpenC2Response", rsp_api), rsp_api)
        self.assertEqual(self.tc.decode("OpenC2Response", rsp_api), rsp_api)
        self._write_examples("t02_query_schema_response",
                             [rsp_api, None, None, None])

    def test03_contain_user(self):
        cmd_api = {
            "action": "contain",
            "target": {
                "user_account": {
                    "user_id": "21942",
                    "account_login": "******",
                    "is_disabled": True,
                    "account_last_login": "******"
                }
            }
        }

        cmd_flat = {
            "action": "contain",
            "target.user_account.user_id": "21942",
            "target.user_account.account_login": "******",
            "target.user_account.is_disabled": True,
            "target.user_account.account_last_login":
            "******"
        }

        cmd_noname = {
            "1": 7,
            "2": {
                "19": {
                    "1": "21942",
                    "2": "jsmith",
                    "8": True,
                    "13": "2017-03-16T07:38:12-04:00"
                }
            }
        }

        cmd_concise = [
            "contain", {
                "user_account": {
                    "user_id": "21942",
                    "account_login": "******",
                    "is_disabled": True,
                    "account_last_login": "******"
                }
            }
        ]

        cmd_min = [
            7, {
                "19": {
                    "1": "21942",
                    "2": "jsmith",
                    "8": True,
                    "13": "2017-03-16T07:38:12-04:00"
                }
            }
        ]

        # Minified (list/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_min)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_min), cmd_api)
        self.tc.set_mode(False, True)  # Concise (list/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_concise)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_concise), cmd_api)
        self.tc.set_mode(True, False)  # unused (dict/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_noname)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_noname), cmd_api)
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(flatten(cmd_api), cmd_flat)
        self.assertEqual(fluff(cmd_flat), cmd_api)
        self._write_examples("t03_contain_user",
                             [cmd_api, cmd_flat, cmd_concise, cmd_min])

    def test03_notify_email_addr(self):
        cmd_api = {
            "action": "notify",
            "target": {
                "email_addr": {
                    "value": "*****@*****.**",
                    "display_name": "Bruce Wayne"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t03_notify_email_addr",
                             [cmd_api, None, None, None])

    def test04_deny_ip(self):
        cmd_api = {
            "action": "deny",
            "target": {
                "ip_connection": {
                    "layer4_protocol": "TCP",
                    "src_addr": {
                        "ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
                    },
                    "src_port": {
                        "number": 10996
                    },
                    "dst_addr": {
                        "ipv4": "1.2.3.5"
                    },
                    "dst_port": {
                        "protocol": "https"
                    }
                }
            },
            "actuator": {
                "network_firewall": {
                    "asset_id": "30"
                }
            },
            "modifiers": {
                "command_id": "pf17_8675309",
                "context": "91",
                "start_time": "2016-11-25T08:10:31-04:00",
                "duration": "PT2M30S"
            }
        }

        cmd_flat = {
            "action": "deny",
            "target.ip_connection.layer4_protocol": "TCP",
            "target.ip_connection.src_addr.ipv6":
            "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
            "target.ip_connection.src_port.number": 10996,
            "target.ip_connection.dst_addr.ipv4": "1.2.3.5",
            "target.ip_connection.dst_port.protocol": "https",
            "actuator.network_firewall.asset_id": "30",
            "modifiers.command_id": "pf17_8675309",
            "modifiers.context": "91",
            "modifiers.start_time": "2016-11-25T08:10:31-04:00",
            "modifiers.duration": "PT2M30S"
        }

        cmd_noname = {
            "1": 6,
            "2": {
                "15": {
                    "1": {
                        "2": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
                    },
                    "2": {
                        "1": 10996
                    },
                    "3": {
                        "1": "1.2.3.5"
                    },
                    "4": {
                        "2": 443
                    },
                    "5": 6
                }
            },
            "3": {
                "14": {
                    "2": "30"
                }
            },
            "4": {
                "1": "91",
                "2": "2016-11-25T08:10:31-04:00",
                "4": "PT2M30S",
                "6": "pf17_8675309"
            }
        }

        cmd_concise = [
            "deny", {
                "ip_connection": [{
                    "ipv6":
                    "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
                }, {
                    "number": 10996
                }, {
                    "ipv4": "1.2.3.5"
                }, {
                    "protocol": "https"
                }, "TCP"]
            }, {
                "network_firewall": [None, "30"]
            }, {
                "context": "91",
                "start_time": "2016-11-25T08:10:31-04:00",
                "duration": "PT2M30S",
                "command_id": "pf17_8675309"
            }
        ]

        cmd_min = [
            6, {
                "15": [{
                    "2": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
                }, {
                    "1": 10996
                }, {
                    "1": "1.2.3.5"
                }, {
                    "2": 443
                }, 6]
            }, {
                "14": [None, "30"]
            }, {
                "1": "91",
                "2": "2016-11-25T08:10:31-04:00",
                "4": "PT2M30S",
                "6": "pf17_8675309"
            }
        ]

        # Minified (list/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_min)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_min), cmd_api)
        self.tc.set_mode(False, True)  # Concise (list/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_concise)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_concise), cmd_api)
        self.tc.set_mode(True, False)  # unused (dict/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_noname)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_noname), cmd_api)
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(flatten(cmd_api), cmd_flat)
        self.assertEqual(fluff(cmd_flat), cmd_api)
        self._write_examples("t04_deny_ip",
                             [cmd_api, cmd_flat, cmd_concise, cmd_min])

    def test05_scan_domain(self):
        cmd_api = {  # API / Verbose (dict/name)
            "action": "scan",
            "target": {
                "domain_name": "www.example.com"
            }
        }

        cmd_flat = {"action": "scan", "target.domain_name": "www.example.com"}

        cmd_noname = {  # unused (dict/tag)
            "1": 1,
            "2": {
                "7": "www.example.com"
            }
        }

        cmd_concise = [  # Concise (list/name)
            "scan", {
                "domain_name": "www.example.com"
            }
        ]

        cmd_min = [1, {"7": "www.example.com"}]

        # Minified (list/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_min)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_min), cmd_api)
        self.tc.set_mode(False, True)  # Concise (list/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_concise)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_concise), cmd_api)
        self.tc.set_mode(True, False)  # unused (dict/tag)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_noname)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_noname), cmd_api)
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(flatten(cmd_api), cmd_flat)
        self.assertEqual(dlist(fluff(cmd_flat)),
                         cmd_api)  # Convert numeric dict to list
        self._write_examples("t05_scan_domain",
                             [cmd_api, cmd_flat, cmd_concise, cmd_min])

    def test06_update_software(self):
        cmd_api = {  # API / Verbose (dict/name)
            "action": "update",
            "target": {
                "software": {
                    "name": "VirusBeGone",
                    "vendor": "McAfmantec"
                }
            },
            "actuator": {
                "process_remediation_service": {
                    "actuator_id": "dns://host03274.example.org"
                }
            },
            "modifiers": {
                "command_id":
                "474074afb389",
                "command_src":
                "dns://orch.example.org",
                "response":
                "ack",
                "source":
                "https://updates.example.org/win7_x64/patch_201704_0137.cab"
            }
        }

        cmd_flat = {
            "action":
            "update",
            "target.software.vendor":
            "McAfmantec",
            "target.software.name":
            "VirusBeGone",
            "actuator.process_remediation_service.actuator_id":
            "dns://host03274.example.org",
            "modifiers.command_id":
            "474074afb389",
            "modifiers.command_src":
            "dns://orch.example.org",
            "modifiers.response":
            "ack",
            "modifiers.source":
            "https://updates.example.org/win7_x64/patch_201704_0137.cab"
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(flatten(cmd_api), cmd_flat)
        self.assertEqual(dlist(fluff(cmd_flat)),
                         cmd_api)  # Convert numeric dict to list
        self._write_examples("t06_update_software",
                             [cmd_api, cmd_flat, None, None])

        # -- Response

        rsp_api = {
            "status": "Processing",
            "statusText": "Updating McAfmantec VirusBeGone ...",
            "response_src": "dns://orch.example.org",
            "command_ref": "474074afb389"
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Response", rsp_api), rsp_api)
        self.assertEqual(self.tc.decode("OpenC2Response", rsp_api), rsp_api)
        self._write_examples("t06_update_software_rsp",
                             [rsp_api, None, None, None])

    def test07_update_file(self):
        cmd_api = {
            "action": "update",
            "target": {
                "file": {
                    "parent_directory": {
                        "path":
                        "\\\\someshared-drive\\somedirectory\\configurations"
                    },
                    "name": "firewallconfiguration.txt"
                }
            },
            "actuator": {
                "network_firewall": {
                    "actuator_id": "dns://host03274.example.org"
                }
            }
        }
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t07_update_file", [cmd_api, None, None, None])

    def test08_negotiation(self):
        cmd_api = {
            "action": "query",
            "target": {
                "openc2": {
                    "comm_supported": ""
                }
            },
            "actuator": {
                "any": {
                    "actuator_id": "https://router7319.example.org"
                }
            }
        }
        rsp_api = {
            "status": "OK",
            "results": {
                "comms": {
                    "serialization": ["JSON", "JSON-min", "XML", "Protobuf"],
                    "connection": [{
                        "DXL": {
                            "channel": "c2-channel"
                        }
                    }]
                }
            }
        }
        cmd2_api = {
            "action": "set",
            "target": {
                "openc2": {
                    "comm_selected": {
                        "serialization": "Protobuf",
                        "connection": {
                            "REST": {
                                "port": {
                                    "protocol": "https"
                                }
                            }
                        }
                    }
                }
            },
            "actuator": {
                "any": {
                    "actuator_id": "https://router7319.example.org"
                }
            }
        }
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.encode("OpenC2Response", rsp_api), rsp_api)
        self.assertEqual(self.tc.decode("OpenC2Response", rsp_api), rsp_api)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd2_api), cmd2_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd2_api), cmd2_api)
        self._write_examples("t08_negotiation1", [cmd_api, None, None, None])
        self._write_examples("t08_negotiation2", [rsp_api, None, None, None])
        self._write_examples("t08_negotiation3", [cmd2_api, None, None, None])

    def test09_cancel_command(self):
        cmd_api = {
            "action": "cancel",
            "target": {
                "openc2": {
                    "command": "b33cd1d4-aeb4-43a3-bfe9-806f4a84ef79"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t09_cancel_command", [cmd_api, None, None, None])

    def test10_delete_email(self):
        cmd_api = {
            "action": "delete",
            "target": {
                "email_message": {
                    "date": "2017-06-07T14:30:31-04:00",
                    "from": {
                        "value": "*****@*****.**"
                    },
                    "subject": "Special Offer!"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t10_delete_email", [cmd_api, None, None, None])

    def test11_restart_process(self):  # TODO: use a real actuator
        cmd_api = {
            "action": "restart",
            "target": {
                "process": {
                    "pid": 17325,
                    "name": "rm -rf /*.*"
                }
            },
            "actuator": {
                "endpoint": {
                    "actuator_id": "dns://i3494.hosts.example.com"
                }
            },
            "modifiers": {
                "method": {
                    "stop": "graceful"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t11_restart_process",
                             [cmd_api, None, None, None])

    def test11_snapshot_process(self):  # TODO: use a real actuator
        cmd_api = {
            "action": "snapshot",
            "target": {
                "process": {
                    "creator_user": {
                        "user_id": "jjadmin"
                    }
                }
            },
            "actuator": {
                "endpoint": {
                    "actuator_id": "dns://i3494.hosts.example.com"
                }
            },
            "modifiers": {
                "method": {
                    "stop": "graceful"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t11_snapshot_process",
                             [cmd_api, None, None, None])

    def test12_locate_ipaddr(self):
        cmd_api = {
            "action": "locate",
            "target": {
                "ipv4_addr": "209.59.128.0/18"
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t12_locate_ipaddr", [cmd_api, None, None, None])

    def test13_redirect_url(self):
        cmd_api = {
            "action": "redirect",
            "target": {
                "url": "https://www.shezuly.com/qqmusic.exe"
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t13_redirect_url", [cmd_api, None, None, None])

    def test14_stop_user_session(self):
        cmd_api = {
            "action": "stop",
            "target": {
                "user_session": {
                    "effective-user": "******",
                    "effective-user-id": "17239",
                    "login-time": "2017-07-03T15:27:14-07:00"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t14_stop_user_session",
                             [cmd_api, None, None, None])

    def test15_report_artifact(self):
        cmd_api = {
            "action": "report",
            "target": {
                "artifact": {
                    "mime_type": "image/jpeg",
                    "hashes": {
                        "MD5":
                        "79bdd30dca09def5b87c55a422382039",
                        "SHA-256":
                        "1cb611150cc54216470836003c503b77b6a6840afd695cb7528b1ca40b82d4e7"
                    }
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t15_report_artifact",
                             [cmd_api, None, None, None])

    def test16_set_registry(self):
        cmd_api = {
            "action": "set",
            "target": {
                "windows_registry_key": {
                    "key":
                    "HKEY_LOCAL_MACHINE\\System\Foo\Bar",
                    "values": [{
                        "name": "Foo",
                        "data": "qwerty",
                        "data_type": "REG_SZ"
                    }]
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t16_set_registry", [cmd_api, None, None, None])

    def test17_investigate_x509_certificate(self):
        cmd_api = {
            "action": "investigate",
            "target": {
                "x509_certificate": {
                    "issuer":
                    "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, "
                    "OU=Certification Services Division, CN=Thawte Server CA/[email protected]",
                    "subject":
                    "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, "
                    "CN=www.freesoft.org/[email protected]",
                    "validity_not_before":
                    "2016-03-12T12:00:00Z",
                    "validity_not_after":
                    "2016-08-21T12:00:00Z"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t17_investigate_x509_certificate",
                             [cmd_api, None, None, None])

    def test18_allow_directory(self):
        cmd_api = {
            "action": "allow",
            "target": {
                "directory": {
                    "path": "C:\\Windows\\System32"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t18_allow_directory",
                             [cmd_api, None, None, None])

    def test19_start_device(self):
        cmd_api = {
            "action": "start",
            "target": {
                "device": {
                    "manufacturer": "Dell",
                    "model": "E3500",
                    "serial_number": "12345CX678"
                }
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("OpenC2Command", cmd_api), cmd_api)
        self.assertEqual(self.tc.decode("OpenC2Command", cmd_api), cmd_api)
        self._write_examples("t19_start_device", [cmd_api, None, None, None])

    def testb1_foo(self):  # Unknown action
        cmd_api = {"action": "foo", "target": {"device": {"model": "bar"}}}
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        with self.assertRaises(ValueError):
            self.tc.encode("OpenC2Command", cmd_api)
        with self.assertRaises(ValueError):
            self.tc.decode("OpenC2Command", cmd_api)

    def testb2_scan(self):  # Unknown target device property
        cmd_api = {"action": "scan", "target": {"device": {"dummy": "bar"}}}
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        with self.assertRaises(ValueError):
            self.tc.encode("OpenC2Command", cmd_api)
        with self.assertRaises(ValueError):
            self.tc.decode("OpenC2Command", cmd_api)

    def testb3_scan(self):  # Extra targets
        cmd_api = {
            "action": "scan",
            "target": {
                "device": {
                    "model": "bar"
                },
                "author":
                "Charles Dickens",
                "title":
                "A Tale of Two Cities",
                "quote":
                "We had everything before us, we had nothing before us, we were all going direct to Heaven, "
                "we were all going direct the other way— in short, the period was so far like the present period, "
                "that some of its noisiest authorities insisted on its being received, for good or for evil, in the "
                "superlative degree of comparison only."
            }
        }
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        with self.assertRaises(ValueError):
            self.tc.encode("OpenC2Command", cmd_api)
        with self.assertRaises(ValueError):
            self.tc.decode("OpenC2Command", cmd_api)
示例#14
0
 def setUp(self):
     jadn_check(schema_bounds)
     self.tc = Codec(schema_bounds)
示例#15
0
class Selectors(unittest.TestCase
                ):  # TODO: bad schema - verify * field has only Choice type
    # TODO: add test cases to decode multiple values for Choice (bad)
    def setUp(self):
        jadn_check(schema_selectors)
        self.tc = Codec(schema_selectors)

    attr1_api = {"type": "Integer", "value": 17}
    attr2_api = {"type": "Primitive", "value": {"count": 17}}
    attr3_api = {
        "type": "Category",
        "value": {
            "animal": {
                "rat": {
                    "length": 21,
                    "weight": .342
                }
            }
        }
    }
    attr4_bad_api = {"type": "Vegetable", "value": "turnip"}
    attr5_bad_api = {"type": "Category", "value": {"animal": {"fish": 10}}}

    def test_attribute_verbose(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.encode("t_attribute", self.attr1_api),
                             self.attr1_api)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr1_api),
                             self.attr1_api)
        self.assertDictEqual(self.tc.encode("t_attribute", self.attr2_api),
                             self.attr2_api)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr2_api),
                             self.attr2_api)
        self.assertDictEqual(self.tc.encode("t_attribute", self.attr3_api),
                             self.attr3_api)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr3_api),
                             self.attr3_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_attribute", self.attr4_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_attribute", self.attr4_bad_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_attribute", self.attr5_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_attribute", self.attr5_bad_api)

    attr1_min = ["Integer", 17]
    attr2_min = ["Primitive", {"7": 17}]
    attr3_min = ["Category", {'2': {'5': [21, 0.342]}}]
    attr4_bad_min = ["Vegetable", {"7": 17}]
    attr5_bad_min = ["Category", {'2': {'9': 10}}]

    def test_attribute_min(self):
        self.tc.set_mode(False, False)
        self.assertListEqual(self.tc.encode("t_attribute", self.attr1_api),
                             self.attr1_min)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr1_min),
                             self.attr1_api)
        self.assertListEqual(self.tc.encode("t_attribute", self.attr2_api),
                             self.attr2_min)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr2_min),
                             self.attr2_api)
        self.assertListEqual(self.tc.encode("t_attribute", self.attr3_api),
                             self.attr3_min)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr3_min),
                             self.attr3_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_attribute", self.attr4_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_attribute", self.attr4_bad_min)
        with self.assertRaises(ValueError):
            self.tc.encode("t_attribute", self.attr5_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_attribute", self.attr5_bad_min)

    pep_api = {"foo": "bar", "data": {"count": 17}}
    pec_api = {
        "foo": "bar",
        "data": {
            "animal": {
                "rat": {
                    "length": 21,
                    "weight": .342
                }
            }
        }
    }
    pep_bad_api = {"foo": "bar", "data": {"turnip": ""}}

    def test_property_explicit_verbose(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(
            self.tc.encode("t_property_explicit_primitive", self.pep_api),
            self.pep_api)
        self.assertDictEqual(
            self.tc.decode("t_property_explicit_primitive", self.pep_api),
            self.pep_api)
        self.assertDictEqual(
            self.tc.encode("t_property_explicit_category", self.pec_api),
            self.pec_api)
        self.assertDictEqual(
            self.tc.decode("t_property_explicit_category", self.pec_api),
            self.pec_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_explicit_primitive", self.pep_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_explicit_primitive", self.pep_bad_api)

    pep_min = ['bar', {'7': 17}]
    pec_min = ['bar', {'2': {'5': [21, 0.342]}}]
    pep_bad_min = ['bar', {'6': 17}]

    def test_property_explicit_min(self):
        self.tc.set_mode(False, False)
        self.assertListEqual(
            self.tc.encode("t_property_explicit_primitive", self.pep_api),
            self.pep_min)
        self.assertDictEqual(
            self.tc.decode("t_property_explicit_primitive", self.pep_min),
            self.pep_api)
        self.assertListEqual(
            self.tc.encode("t_property_explicit_category", self.pec_api),
            self.pec_min)
        self.assertDictEqual(
            self.tc.decode("t_property_explicit_category", self.pec_min),
            self.pec_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_explicit_primitive", self.pep_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_explicit_primitive", self.pep_bad_min)

    pip_api = {"foo": "bar", "count": 17}
    pic_api = {"foo": "bar", "animal": {"rat": {"length": 21, "weight": .342}}}
    pip_bad1_api = {"foo": "bar", "value": "turnip"}
    pip_bad2_api = {"foo": "bar", "value": {"turnip": ""}}

    def test_property_implicit_verbose(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(
            self.tc.encode("t_property_implicit_primitive", self.pip_api),
            self.pip_api)
        self.assertDictEqual(
            self.tc.decode("t_property_implicit_primitive", self.pip_api),
            self.pip_api)
        self.assertDictEqual(
            self.tc.encode("t_property_implicit_category", self.pic_api),
            self.pic_api)
        self.assertDictEqual(
            self.tc.decode("t_property_implicit_category", self.pic_api),
            self.pic_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_implicit_primitive", self.pip_bad1_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_implicit_primitive", self.pip_bad1_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_implicit_primitive", self.pip_bad2_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_implicit_primitive", self.pip_bad2_api)

    pip_min = ["bar", {"7": 17}]
    pic_min = ["bar", {"2": {"5": [21, .342]}}]
    pip_bad1_min = []
    pip_bad2_min = []

    def test_property_implicit_min(self):
        self.tc.set_mode(False, False)
        self.assertListEqual(
            self.tc.encode("t_property_implicit_primitive", self.pip_api),
            self.pip_min)
        self.assertDictEqual(
            self.tc.decode("t_property_implicit_primitive", self.pip_min),
            self.pip_api)
        self.assertListEqual(
            self.tc.encode("t_property_implicit_category", self.pic_api),
            self.pic_min)
        self.assertDictEqual(
            self.tc.decode("t_property_implicit_category", self.pic_min),
            self.pic_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_implicit_primitive", self.pip_bad1_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_implicit_primitive", self.pip_bad1_min)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_implicit_primitive", self.pip_bad2_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_implicit_primitive", self.pip_bad2_min)
示例#16
0
 def setUp(self):
     jadn_check(schema_compound)
     self.tc = Codec(schema_compound)
示例#17
0
 def setUp(self):
     jadn_check(schema_basic)
     self.tc = Codec(schema_basic)
示例#18
0
class BasicTypes(unittest.TestCase):  # TODO: Test Array
    def setUp(self):
        jadn_check(schema_basic)
        self.tc = Codec(schema_basic)

    def test_primitive(self):  # Non-composed types (bool, int, num, str)
        self.assertEqual(self.tc.decode("t_bool", True), True)
        self.assertEqual(self.tc.decode("t_bool", False), False)
        self.assertEqual(self.tc.encode("t_bool", True), True)
        self.assertEqual(self.tc.encode("t_bool", False), False)
        with self.assertRaises(TypeError):
            self.tc.decode("t_bool", "True")
        with self.assertRaises(TypeError):
            self.tc.decode("t_bool", 1)
        with self.assertRaises(TypeError):
            self.tc.encode("t_bool", "True")
        with self.assertRaises(TypeError):
            self.tc.encode("t_bool", 1)

        self.assertEqual(self.tc.decode("t_int", 35), 35)
        self.assertEqual(self.tc.encode("t_int", 35), 35)
        with self.assertRaises(TypeError):
            self.tc.decode("t_int", 35.4)
        with self.assertRaises(TypeError):
            self.tc.decode("t_int", True)
        with self.assertRaises(TypeError):
            self.tc.decode("t_int", "hello")
        with self.assertRaises(TypeError):
            self.tc.encode("t_int", 35.4)
        with self.assertRaises(TypeError):
            self.tc.encode("t_int", True)
        with self.assertRaises(TypeError):
            self.tc.encode("t_int", "hello")

        self.assertEqual(self.tc.decode("t_num", 25.96), 25.96)
        self.assertEqual(self.tc.decode("t_num", 25), 25)
        self.assertEqual(self.tc.encode("t_num", 25.96), 25.96)
        self.assertEqual(self.tc.encode("t_num", 25), 25)
        with self.assertRaises(TypeError):
            self.tc.decode("t_num", True)
        with self.assertRaises(TypeError):
            self.tc.decode("t_num", "hello")
        with self.assertRaises(TypeError):
            self.tc.encode("t_num", True)
        with self.assertRaises(TypeError):
            self.tc.encode("t_num", "hello")

        self.assertEqual(self.tc.decode("t_str", "parrot"), "parrot")
        self.assertEqual(self.tc.encode("t_str", "parrot"), "parrot")
        with self.assertRaises(TypeError):
            self.tc.decode("t_str", True)
        with self.assertRaises(TypeError):
            self.tc.decode("t_str", 1)
        with self.assertRaises(TypeError):
            self.tc.encode("t_str", True)
        with self.assertRaises(TypeError):
            self.tc.encode("t_str", 1)

    def test_array_of(self):
        self.assertEqual(self.tc.decode("t_array_of", [1, 4, 9, 16]),
                         [1, 4, 9, 16])
        self.assertEqual(self.tc.encode("t_array_of", [1, 4, 9, 16]),
                         [1, 4, 9, 16])
        with self.assertRaises(TypeError):
            self.tc.decode("t_array_of", [1, "4", 9, 16])
        with self.assertRaises(TypeError):
            self.tc.decode("t_array_of", 9)
        with self.assertRaises(TypeError):
            self.tc.encode("t_array_of", [1, "4", 9, 16])
        with self.assertRaises(TypeError):
            self.tc.decode("t_array_of", 9)

    B1b = b"data to be encoded"
    B1s = "ZGF0YSB0byBiZSBlbmNvZGVk"
    B2b = "data\nto be ëncoded 旅程".encode(encoding="UTF-8")
    B2s = "ZGF0YQp0byBiZSDDq25jb2RlZCDml4XnqIs="
    B3b = binascii.a2b_hex(
        "18e0c9987b8f32417ca6744f544b815ad2a6b4adca69d2c310bd033c57d363e3")
    B3s = "GODJmHuPMkF8pnRPVEuBWtKmtK3KadLDEL0DPFfTY+M="
    B_bad1b = "string"
    B_bad2b = 394
    B_bad3b = True
    B_bad1s = "ZgF%&0B++"

    def test_binary(self):
        self.assertEqual(self.tc.decode("t_bin", self.B1s), self.B1b)
        self.assertEqual(self.tc.decode("t_bin", self.B2s), self.B2b)
        self.assertEqual(self.tc.decode("t_bin", self.B3s), self.B3b)
        self.assertEqual(self.tc.encode("t_bin", self.B1b), self.B1s)
        self.assertEqual(self.tc.encode("t_bin", self.B2b), self.B2s)
        self.assertEqual(self.tc.encode("t_bin", self.B3b), self.B3s)
        with self.assertRaises((TypeError, binascii.Error)):
            self.tc.decode("t_bin", self.B_bad1s)
        with self.assertRaises(TypeError):
            self.tc.encode("t_bin", self.B_bad1b)
        with self.assertRaises(TypeError):
            self.tc.encode("t_bin", self.B_bad2b)
        with self.assertRaises(TypeError):
            self.tc.encode("t_bin", self.B_bad3b)

    C1a = {"type1": "foo"}
    C2a = {"type2": False}
    C3a = {"type3": 42}
    C1m = {"1": "foo"}
    C2m = {"4": False}
    C3m = {"7": 42}
    C1_bad1a = {"type1": 15}
    C1_bad2a = {"type5": "foo"}
    C1_bad3a = {"type1": "foo", "type2": False}
    C1_bad1m = {"1": 15}
    C1_bad2m = {"3": "foo"}
    C1_bad3m = {"1": "foo", "4": False}
    C1_bad4m = {1: "foo"}

    def test_choice_min(self):
        self.assertEqual(self.tc.decode("t_choice", self.C1m), self.C1a)
        self.assertEqual(self.tc.decode("t_choice", self.C2m), self.C2a)
        self.assertEqual(self.tc.decode("t_choice", self.C3m), self.C3a)
        self.assertEqual(self.tc.encode("t_choice", self.C1a), self.C1m)
        self.assertEqual(self.tc.encode("t_choice", self.C2a), self.C2m)
        self.assertEqual(self.tc.encode("t_choice", self.C3a), self.C3m)
        with self.assertRaises(TypeError):
            self.tc.decode("t_choice", self.C1_bad1m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_choice", self.C1_bad2m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_choice", self.C1_bad3m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_choice", self.C1_bad4m)
        with self.assertRaises(TypeError):
            self.tc.encode("t_choice", self.C1_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_choice", self.C1_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_choice", self.C1_bad3a)

    def test_choice_verbose(self):
        self.tc.set_mode(True, True)
        self.assertEqual(self.tc.decode("t_choice", self.C1a), self.C1a)
        self.assertEqual(self.tc.decode("t_choice", self.C2a), self.C2a)
        self.assertEqual(self.tc.decode("t_choice", self.C3a), self.C3a)
        self.assertEqual(self.tc.encode("t_choice", self.C1a), self.C1a)
        self.assertEqual(self.tc.encode("t_choice", self.C2a), self.C2a)
        self.assertEqual(self.tc.encode("t_choice", self.C3a), self.C3a)

        with self.assertRaises(TypeError):
            self.tc.decode("t_choice", self.C1_bad1a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_choice", self.C1_bad2a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_choice", self.C1_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_choice", self.C1_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_choice", self.C1_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_choice", self.C1_bad3a)

    def test_enumerated_min(self):
        self.assertEqual(self.tc.decode("t_enum", 15), "extra")
        self.assertEqual(self.tc.encode("t_enum", "extra"), 15)
        with self.assertRaises(ValueError):
            self.tc.decode("t_enum", 13)
        with self.assertRaises(TypeError):
            self.tc.decode("t_enum", "extra")
        with self.assertRaises(TypeError):
            self.tc.decode("t_enum", ["first"])
        with self.assertRaises(ValueError):
            self.tc.encode("t_enum", "foo")
        with self.assertRaises(TypeError):
            self.tc.encode("t_enum", 15)
        with self.assertRaises(TypeError):
            self.tc.encode("t_enum", [1])

    def test_enumerated_verbose(self):
        self.tc.set_mode(True, True)
        self.assertEqual(self.tc.decode("t_enum", "extra"), "extra")
        self.assertEqual(self.tc.encode("t_enum", "extra"), "extra")
        with self.assertRaises(ValueError):
            self.tc.decode("t_enum", "foo")
        with self.assertRaises(TypeError):
            self.tc.decode("t_enum", 42)
        with self.assertRaises(TypeError):
            self.tc.decode("t_enum", ["first"])
        with self.assertRaises(ValueError):
            self.tc.encode("t_enum", "foo")
        with self.assertRaises(TypeError):
            self.tc.encode("t_enum", 42)
        with self.assertRaises(TypeError):
            self.tc.encode("t_enum", ["first"])

    def test_enumerated_comp_min(self):
        self.assertEqual(self.tc.decode("t_enum_c", 15), 15)
        self.assertEqual(self.tc.encode("t_enum_c", 15), 15)
        with self.assertRaises(TypeError):
            self.tc.decode("t_enum_c", "extra")
        with self.assertRaises(TypeError):
            self.tc.encode("t_enum_c", "extra")

    def test_enumerated_comp_verbose(self):
        self.tc.set_mode(True, True)
        self.assertEqual(self.tc.decode("t_enum_c", 15), 15)
        self.assertEqual(self.tc.encode("t_enum_c", 15), 15)
        with self.assertRaises(TypeError):
            self.tc.decode("t_enum_c", "extra")
        with self.assertRaises(TypeError):
            self.tc.encode("t_enum_c", "extra")

    RGB1 = {
        "red": 24,
        "green": 120,
        "blue": 240
    }  # API (decoded) and verbose values Map and Record
    RGB2 = {"red": 50, "blue": 100}
    RGB3 = {"red": 9, "green": 80, "blue": 96, "alpha": 128}
    RGB_bad1a = {"red": 24, "green": 120}
    RGB_bad2a = {"red": 9, "green": 80, "blue": 96, "beta": 128}
    RGB_bad3a = {"red": 9, "green": 80, "blue": 96, "alpha": 128, "beta": 196}
    RGB_bad4a = {"red": "four", "green": 120, "blue": 240}
    RGB_bad5a = {"red": 24, "green": "120", "blue": 240}
    RGB_bad6a = {"red": 24, "green": 120, "bleu": 240}
    RGB_bad7a = {2: 24, "green": 120, "blue": 240}

    Map1m = {
        "2": 24,
        "4": 120,
        "6": 240
    }  # Encoded values Map (minimized and dict/tag mode)
    Map2m = {"2": 50, "6": 100}
    Map3m = {"2": 9, "4": 80, "6": 96, "9": 128}
    Map_bad1m = {"2": 24, "4": 120}
    Map_bad2m = {"2": 9, "4": 80, "6": 96, "9": 128, "12": 42}
    Map_bad3m = {"2": "four", "4": 120, "6": 240}
    Map_bad4m = {2: 24, 4: 120, 6: 240}
    Map_bad5m = [24, 120, 240]

    Rec1m = [24, 120, 240]  # Encoded values Record (minimized)
    Rec2m = [50, None, 100]
    Rec3m = [9, 80, 96, 128]
    Rec_bad1m = [24, 120]
    Rec_bad2m = [9, 80, 96, 128, 42]
    Rec_bad3m = ["four", 120, 240]

    Rec1n = {
        "1": 24,
        "2": 120,
        "3": 240
    }  # Encoded values Record (unused dict/tag mode)
    Rec2n = {"1": 50, "3": 100}
    Rec3n = {"1": 9, "2": 80, "3": 96, "4": 128}
    Rec_bad1n = {"1": 24, "2": 120}
    Rec_bad2n = {"1": 9, "2": 80, "3": 96, "4": 128, "5": 42}
    Rec_bad3n = {"1": "four", "2": 120, "3": 240}
    Rec_bad4n = {1: 24, 2: 120, 3: 240}

    RGB1c = [24, 120, 240]  # Encoded values Record (concise)
    RGB2c = [50, None, 100]
    RGB3c = [9, 80, 96, 128]
    RGB_bad1c = [24, 120]
    RGB_bad2c = [9, 80, 96, 128, 42]
    RGB_bad3c = ["four", 120, 240]

    def test_map_min(self):  # dict structure, identifier tag
        self.assertDictEqual(self.tc.decode("t_map", self.Map1m), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_map", self.Map2m), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_map", self.Map3m), self.RGB3)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB1), self.Map1m)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB2), self.Map2m)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB3), self.Map3m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.Map_bad1m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.Map_bad2m)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.Map_bad3m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.Map_bad4m)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.Map_bad5m)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_map_unused(self):  # dict structure, identifier tag
        self.tc.set_mode(True, False)
        self.assertDictEqual(self.tc.decode("t_map", self.Map1m), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_map", self.Map2m), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_map", self.Map3m), self.RGB3)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB1), self.Map1m)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB2), self.Map2m)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB3), self.Map3m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.Map_bad1m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.Map_bad2m)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.Map_bad3m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.Map_bad4m)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_map_concise(self):  # dict structure, identifier name
        self.tc.set_mode(False, True)
        self.assertDictEqual(self.tc.decode("t_map", self.RGB1), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_map", self.RGB2), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_map", self.RGB3), self.RGB3)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB1), self.RGB1)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB2), self.RGB2)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB3), self.RGB3)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad7a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_map_verbose(self):  # dict structure, identifier name
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.decode("t_map", self.RGB1), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_map", self.RGB2), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_map", self.RGB3), self.RGB3)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB1), self.RGB1)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB2), self.RGB2)
        self.assertDictEqual(self.tc.encode("t_map", self.RGB3), self.RGB3)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad7a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_record_min(self):
        self.assertDictEqual(self.tc.decode("t_rec", self.Rec1m), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_rec", self.Rec2m), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_rec", self.Rec3m), self.RGB3)
        self.assertEqual(self.tc.encode("t_rec", self.RGB1), self.Rec1m)
        self.assertEqual(self.tc.encode("t_rec", self.RGB2), self.Rec2m)
        self.assertEqual(self.tc.encode("t_rec", self.RGB3), self.Rec3m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.Rec_bad1m)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.Rec_bad2m)
        with self.assertRaises(TypeError):
            self.tc.decode("t_rec", self.Rec_bad3m)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_record_unused(self):
        self.tc.set_mode(True, False)
        self.assertDictEqual(self.tc.decode("t_rec", self.Rec1n), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_rec", self.Rec2n), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_rec", self.Rec3n), self.RGB3)
        self.assertEqual(self.tc.encode("t_rec", self.RGB1), self.Rec1n)
        self.assertEqual(self.tc.encode("t_rec", self.RGB2), self.Rec2n)
        self.assertEqual(self.tc.encode("t_rec", self.RGB3), self.Rec3n)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.Rec_bad1n)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.Rec_bad2n)
        with self.assertRaises(TypeError):
            self.tc.decode("t_rec", self.Rec_bad3n)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.Rec_bad4n)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_record_concise(self):
        self.tc.set_mode(False, True)
        self.assertDictEqual(self.tc.decode("t_rec", self.RGB1c), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_rec", self.RGB2c), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_rec", self.RGB3c), self.RGB3)
        self.assertEqual(self.tc.encode("t_rec", self.RGB1), self.RGB1c)
        self.assertEqual(self.tc.encode("t_rec", self.RGB2), self.RGB2c)
        self.assertEqual(self.tc.encode("t_rec", self.RGB3), self.RGB3c)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.RGB_bad1c)
        with self.assertRaises(ValueError):
            self.tc.decode("t_rec", self.RGB_bad2c)
        with self.assertRaises(TypeError):
            self.tc.decode("t_rec", self.RGB_bad3c)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_record_verbose(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.decode("t_rec", self.RGB1), self.RGB1)
        self.assertDictEqual(self.tc.decode("t_rec", self.RGB2), self.RGB2)
        self.assertDictEqual(self.tc.decode("t_rec", self.RGB3), self.RGB3)
        self.assertDictEqual(self.tc.encode("t_rec", self.RGB1), self.RGB1)
        self.assertDictEqual(self.tc.encode("t_rec", self.RGB2), self.RGB2)
        self.assertDictEqual(self.tc.encode("t_rec", self.RGB3), self.RGB3)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.decode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_map", self.RGB_bad7a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad1a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad3a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad4a)
        with self.assertRaises(TypeError):
            self.tc.encode("t_map", self.RGB_bad5a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad6a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_map", self.RGB_bad7a)

    def test_array(self):  # TODO: verbose and min, vector of unnamed fields
        pass
示例#19
0
class Experimental_IPv6_Addr(unittest.TestCase):

    def setUp(self):
        fn = os.path.join('schema', 'exp.jadn')  # Load experimental OpenC2 schema
        schema = jadn_load(fn)
        sa = jadn_analyze(schema)
        if sa['undefined']:
            print('Warning - undefined:', sa['undefined'])
        self.tc = Codec(schema, verbose_rec=True, verbose_str=True)

    ipv6_addr_b64_api = {           # API IPv6 address.  All API values are identical except for name.
        'ipv6_addr_b64': b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH'}

    ipv6_addr_b64_ser = {           # IPv6 address serialized in Base64url format
        'ipv6_addr_b64': 'IAENuIWjCNMTGYouA3BzSA'}

    ipv6_addr_hex_api = {           # API IPv6 address.  All API values are identical except for name.
        'ipv6_addr_x': b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH'}

    ipv6_addr_hex_ser = {           # IPv6 address serialized in hex format
        'ipv6_addr_x': '20010DB885A308D313198A2E03707348'}

    ipv6_addr_str_api = {           # API IPv6 address.  All API values are identical except for name.
        'ipv6_addr_s': b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH'}

    ipv6_addr_str_ser = {           # IPv6 address serialized in type-specific string (dotted decimal) format
        'ipv6_addr_s': '2001:db8:85a3:8d3:1319:8a2e:370:7348'}

    ipv6_addr_b64_api_bad1 = {      # Bad API IPv6 address - too short
        'ipv6_addr_s': b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03ps'}

    ipv6_addr_b64_api_bad2 = {      # Bad API IPv6 address - too long
        'ipv6_addr_s': b' \x01\r\xb8\x85\xa3\x08\xd3\x13\x19\x8a.\x03psH\x01'}

    ipv6_addr_hex_ser_bad1 = {      # Bad IPv6 address - too short
        'ipv6_addr_x': '20010DB885A308D313198A2E037073'}

    ipv6_addr_hex_ser_bad2 = {      # Bad IPv6 address - too long
        'ipv6_addr_x': '20010DB885A308D313198A2E0370734801'}

    ipv6_addr_hex_ser_bad3 = {      # Bad IPv6 address - punctuation
        'ipv6_addr_x': '2001:0DB8:85A3:08D3:1319:8A2E:0370:7348'}

    ipv6_addr_hex_ser_bad4 = {      # Bad IPv6 address - lower case
        'ipv6_addr_x': '20010db885a308d313198a2e03707348'}

    ipv6_addr_hex_ser_bad5 = {      # Bad IPv6 address - spaces
        'ipv6_addr_x': '2001 0DB8 85A3 08D3 1319 8A2E 0370 7348'}

    ipv6_addr_str_ser_bad1 = {      # Bad IPv6 address - too long
        'ipv6_addr_s': '2001:db8:85a3:8d3:1319:8a2e:370:7348:0123'}

    ipv6_addr_str_ser_bad2 = {      # Bad IPv6 address - leading zero
        'ipv6_addr_s': '2001:0db8:85a3:08d3:1319:8a2e:0370:7348'}

    ipv6_addr_str_ser_bad3 = {      # Bad IPv6 address - wrong punctuation
        'ipv6_addr_s': '2001.db8.85a3.8d3.1319.8a2e.370.7348'}

    def test_ipv6_b64(self):
        self.assertEqual(self.tc.encode('Target', self.ipv6_addr_b64_api), self.ipv6_addr_b64_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv6_addr_b64_ser), self.ipv6_addr_b64_api)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv6_addr_b64_api_bad1)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv6_addr_b64_api_bad2)

    def test_ipv6_hex(self):
        self.assertEqual(self.tc.encode('Target', self.ipv6_addr_hex_api), self.ipv6_addr_hex_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv6_addr_hex_ser), self.ipv6_addr_hex_api)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv6_addr_hex_ser_bad1)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv6_addr_hex_ser_bad2)
        with self.assertRaises(TypeError):
            self.tc.decode('Target', self.ipv6_addr_hex_ser_bad3)
        with self.assertRaises(TypeError):
            self.tc.decode('Target', self.ipv6_addr_hex_ser_bad4)
        with self.assertRaises(TypeError):
            self.tc.decode('Target', self.ipv6_addr_hex_ser_bad5)

    def test_ipv6_str(self):
        self.assertEqual(self.tc.encode('Target', self.ipv6_addr_str_api), self.ipv6_addr_str_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv6_addr_str_ser), self.ipv6_addr_str_api)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv6_addr_str_ser_bad1)
#        with self.assertRaises(ValueError):    # https://tools.ietf.org/html/draft-main-ipaddr-text-rep-02#section-3
#            self.tc.decode('Target', self.ipv6_addr_str_ser_bad2)      # leading zeroes are not used
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv6_addr_str_ser_bad3)
class Relax1(unittest.TestCase):
    def setUp(self):
        schema = jadn_load(os.path.join("schema", "relax1.jadn"))
        self.tc = Codec(schema)

    def test1_property_syntax(self):
        msg_api = [{
            "name": "John Smith",
            "email": "*****@*****.**"
        }, {
            "name": "Fred Bloggs",
            "email": "*****@*****.**",
            "note": "Dr."
        }]
        msg_min = [["John Smith", "*****@*****.**"],
                   ["Fred Bloggs", "*****@*****.**", "Dr."]]

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("addressBook", msg_api), msg_api)
        self.assertEqual(self.tc.decode("addressBook", msg_api), msg_api)
        self.tc.set_mode(False, False)  # Minified (list/tag)
        self.assertEqual(self.tc.encode("addressBook", msg_api), msg_min)
        self.assertEqual(self.tc.decode("addressBook", msg_min), msg_api)

    def test2_card_explicit(self):
        msg_api = {
            "name": "John Smith",
            "email": "*****@*****.**",
            "info": {
                "phone": "555-1234"
            }
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("card2", msg_api), msg_api)
        self.assertEqual(self.tc.decode("card2", msg_api), msg_api)

    def test3_card_implicit(self):
        msg_api = {
            "name": "John Smith",
            "email": "*****@*****.**",
            "phone": "555-1234"
        }

        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode("card2", msg_api), msg_api)
        self.assertEqual(self.tc.decode("card2", msg_api), msg_api)
示例#21
0
class Experimental_IPv4_Addr(unittest.TestCase):

    def setUp(self):
        fn = os.path.join('schema', 'exp.jadn')        # Load experimental OpenC2 schema
        schema = jadn_load(fn)
        sa = jadn_analyze(schema)
        if sa['undefined']:
            print('Warning - undefined:', sa['undefined'])
        self.tc = Codec(schema, verbose_rec=True, verbose_str=True)

    ipv4_addr_b64_api = {           # API IPv4 address.  All API values are identical except for name.
        'ipv4_addr_b64': b'\xc0\xa8\x00\xfe'}

    ipv4_addr_b64_ser = {           # IPv4 address serialized in Base64url format
        'ipv4_addr_b64': 'wKgA_g'}

    ipv4_addr_hex_api = {           # API IPv4 address.  All API values are identical except for name.
        'ipv4_addr_x': b'\xc0\xa8\x00\xfe'}

    ipv4_addr_hex_ser = {           # IPv4 address serialized in hex format
        'ipv4_addr_x': 'C0A800FE'}

    ipv4_addr_str_api = {           # API IPv4 address.  All API values are identical except for name.
        'ipv4_addr_s': b'\xc0\xa8\x00\xfe'}

    ipv4_addr_str_ser = {           # IPv4 address serialized in type-specific string (dotted decimal) format
        'ipv4_addr_s': '192.168.0.254'}

    ipv4_addr_b64_api_bad1 = {  # Bad API IPv4 address - too short
        'ipv4_addr_s': b'\xc0\xa8\x00'}

    ipv4_addr_b64_api_bad2 = {  # Bad API IPv4 address - too long
        'ipv4_addr_s': b'\xc0\xa8\x00\xfe\x02'}

    ipv4_addr_hex_ser_bad1 = {      # Bad IPv4 address - too short
        'ipv4_addr_x': 'C0A800'}

    ipv4_addr_hex_ser_bad2 = {      # Bad IPv4 address - too long
        'ipv4_addr_x': 'C0A800FE02'}

    ipv4_addr_hex_ser_bad3 = {      # Bad IPv4 address - punctuation
        'ipv4_addr_x': 'C0A8:00FE'}

    ipv4_addr_hex_ser_bad4 = {      # Bad IPv4 address - lower case
        'ipv4_addr_x': 'C0a800fe'}

    ipv4_addr_hex_ser_bad5 = {      # Bad IPv4 address - spaces
        'ipv4_addr_x': 'C0 A8 00 FE'}

    ipv4_addr_str_ser_bad1 = {      # Bad IPv4 address - too long
        'ipv4_addr_s': '192.168.0.254.2'}

    ipv4_addr_str_ser_bad2 = {      # Bad IPv4 address - leading zero
        'ipv4_addr_s': '192.168.0.054'}

    ipv4_addr_str_ser_bad3 = {      # Bad IPv4 address - wrong punctuation
        'ipv4_addr_s': '192:168:0:54'}

    ipv4_addr_str_ser_bad4 = {      # Bad IPv4 address - non-decimal
        'ipv4_addr_s': '192.168.0.5a'}

    def test_ipv4_b64(self):
        self.assertEqual(self.tc.encode('Target', self.ipv4_addr_b64_api), self.ipv4_addr_b64_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv4_addr_b64_ser), self.ipv4_addr_b64_api)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv4_addr_b64_api_bad1)
        with self.assertRaises(ValueError):
            self.tc.encode('Target', self.ipv4_addr_b64_api_bad2)

    def test_ipv4_hex(self):
        self.assertEqual(self.tc.encode('Target', self.ipv4_addr_hex_api), self.ipv4_addr_hex_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv4_addr_hex_ser), self.ipv4_addr_hex_api)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_addr_hex_ser_bad1)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_addr_hex_ser_bad2)
        with self.assertRaises(TypeError):
            self.tc.decode('Target', self.ipv4_addr_hex_ser_bad3)
        with self.assertRaises(TypeError):
            self.tc.decode('Target', self.ipv4_addr_hex_ser_bad4)
        with self.assertRaises(TypeError):
            self.tc.decode('Target', self.ipv4_addr_hex_ser_bad5)

    def test_ipv4_str(self):
        self.assertEqual(self.tc.encode('Target', self.ipv4_addr_str_api), self.ipv4_addr_str_ser)
        self.assertEqual(self.tc.decode('Target', self.ipv4_addr_str_ser), self.ipv4_addr_str_api)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_addr_str_ser_bad1)
#        with self.assertRaises(ValueError):    # https://tools.ietf.org/html/draft-main-ipaddr-text-rep-02#section-3
#            self.tc.decode('Target', self.ipv4_addr_str_ser_bad2)      # leading zeroes are not used
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_addr_str_ser_bad3)
        with self.assertRaises(ValueError):
            self.tc.decode('Target', self.ipv4_addr_str_ser_bad4)
示例#22
0
class Selectors(unittest.TestCase):

    def setUp(self):
        jadn_check(schema_selectors)
        self.tc = Codec(schema_selectors)

    attr1_api = {"type": "Integer", "value": 17}
    attr2_api = {"type": "Primitive", "value": {"count": 17}}
    attr3_api = {"type": "Category", "value": {"animal": {"rat": {"length": 21, "weight": .342}}}}
    attr4_bad_api = {"type": "vegetable", "value": "turnip"}
    attr5_bad_api = {"type": "vegetable", "value": {"turnip": ""}}

    def test_attribute(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.encode("t_attribute", self.attr1_api), self.attr1_api)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr1_api), self.attr1_api)
        self.assertDictEqual(self.tc.encode("t_attribute", self.attr2_api), self.attr2_api)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr2_api), self.attr2_api)
        self.assertDictEqual(self.tc.encode("t_attribute", self.attr3_api), self.attr3_api)
        self.assertDictEqual(self.tc.decode("t_attribute", self.attr3_api), self.attr3_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_attribute", self.attr4_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_attribute", self.attr4_bad_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_attribute", self.attr5_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_attribute", self.attr5_bad_api)

    pep_api = {"foo": "bar", "data": {"count": 17}}
    pec_api = {"foo": "bar", "data": {"animal": {"rat": {"length": 21, "weight": .342}}}}
    pep_bad_api = {"foo": "bar", "data": {"turnip": ""}}

    def test_property_explicit(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.encode("t_property_explicit_primitive", self.pep_api), self.pep_api)
        self.assertDictEqual(self.tc.decode("t_property_explicit_primitive", self.pep_api), self.pep_api)
        self.assertDictEqual(self.tc.encode("t_property_explicit_category", self.pec_api), self.pec_api)
        self.assertDictEqual(self.tc.decode("t_property_explicit_category", self.pec_api), self.pec_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_explicit_primitive", self.pep_bad_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_explicit_primitive", self.pep_bad_api)

    pip_api = {"foo": "bar", "count": 17}
    pic_api = {"foo": "bar", "animal": {"rat": {"length": 21, "weight": .342}}}
    pip_bad1_api = {"foo": "bar", "value": "turnip"}
    pip_bad2_api = {"foo": "bar", "value": {"turnip": ""}}

    def test_property_implicit(self):
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.encode("t_property_implicit_primitive", self.pip_api), self.pip_api)
        self.assertDictEqual(self.tc.decode("t_property_implicit_primitive", self.pip_api), self.pip_api)
        self.assertDictEqual(self.tc.encode("t_property_implicit_category", self.pic_api), self.pic_api)
        self.assertDictEqual(self.tc.decode("t_property_implicit_category", self.pic_api), self.pic_api)
        with self.assertRaises(TypeError):
            self.tc.encode("t_property_implicit_primitive", self.pip_bad1_api)
        with self.assertRaises(TypeError):
            self.tc.decode("t_property_implicit_primitive", self.pip_bad1_api)
        with self.assertRaises(ValueError):
            self.tc.encode("t_property_implicit_primitive", self.pip_bad2_api)
        with self.assertRaises(ValueError):
            self.tc.decode("t_property_implicit_primitive", self.pip_bad2_api)
示例#23
0
 def setUp(self):
     jadn_check(schema_selectors)
     self.tc = Codec(schema_selectors)
示例#24
0
 def setUp(self):
     jadn_check(schema_person)
     jadn_analyze(schema_person)
     self.c = Codec(schema_person, "True",
                    "True")  # Verbose encoding mode (dict/name)
示例#25
0
class ListField(
        unittest.TestCase
):  # TODO: arrayOf(rec,map,array,arrayof,choice), array(), map(), rec()
    def setUp(self):
        jadn_check(schema_listfield)
        self.tc = Codec(schema_listfield)

    Lna = {
        "string": "cat"
    }  # Cardinality 0..n field doesn't omit empty list.  Use ArrayOf type.
    Lsa = {
        "string": "cat",
        "list": "red"
    }  # Always invalid, value is a string, not a list of one string.
    L0a = {
        "string": "cat",
        "list": []
    }  # List fields SHOULD have minimum cardinality 1 to prevent this ambiguity.
    L1a = {"string": "cat", "list": ["red"]}
    L2a = {"string": "cat", "list": ["red", "green"]}
    L3a = {"string": "cat", "list": ["red", "green", "blue"]}

    def test_opt_list_verbose(self):  # n-P, s-F, 0-F, 1-P, 2-P, 3-F
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.encode("t_opt_list", self.Lna), self.Lna)
        self.assertDictEqual(self.tc.decode("t_opt_list", self.Lna), self.Lna)
        with self.assertRaises(TypeError):
            self.tc.encode("t_opt_list", self.Lsa)
        with self.assertRaises(TypeError):
            self.tc.decode("t_opt_list", self.Lsa)
        with self.assertRaises(ValueError):
            self.tc.encode("t_opt_list", self.L0a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_opt_list", self.L0a)
        self.assertDictEqual(self.tc.encode("t_opt_list", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.decode("t_opt_list", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.encode("t_opt_list", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.decode("t_opt_list", self.L2a), self.L2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_opt_list", self.L3a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_opt_list", self.L3a)

    def test_list_1_2_verbose(self):  # n-F, s-F, 0-F, 1-P, 2-P, 3-F
        self.tc.set_mode(True, True)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_1_2", self.Lna)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_1_2", self.Lna)
        with self.assertRaises(TypeError):
            self.tc.encode("t_list_1_2", self.Lsa)
        with self.assertRaises(TypeError):
            self.tc.decode("t_list_1_2", self.Lsa)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_1_2", self.L0a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_1_2", self.L0a)
        self.assertDictEqual(self.tc.encode("t_list_1_2", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.decode("t_list_1_2", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.encode("t_list_1_2", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.decode("t_list_1_2", self.L2a), self.L2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_1_2", self.L3a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_1_2", self.L3a)

    def test_list_0_2_verbose(self):  # n-P, s-F, 0-F, 1-P, 2-P, 3-F
        self.tc.set_mode(True, True)
        self.assertDictEqual(self.tc.encode("t_list_0_2", self.Lna), self.Lna)
        self.assertDictEqual(self.tc.decode("t_list_0_2", self.Lna), self.Lna)
        with self.assertRaises(TypeError):
            self.tc.encode("t_list_0_2", self.Lsa)
        with self.assertRaises(TypeError):
            self.tc.decode("t_list_0_2", self.Lsa)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_0_2", self.L0a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_0_2", self.L0a)
        self.assertDictEqual(self.tc.encode("t_list_0_2", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.decode("t_list_0_2", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.encode("t_list_0_2", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.decode("t_list_0_2", self.L2a), self.L2a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_0_2", self.L3a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_0_2", self.L3a)

    def test_list_2_3_verbose(self):  # n-F, 0-F, 1-F, 2-P, 3-P
        self.tc.set_mode(True, True)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_2_3", self.Lna)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_2_3", self.Lna)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_2_3", self.L0a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_2_3", self.L0a)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_2_3", self.L1a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_2_3", self.L1a)
        self.assertDictEqual(self.tc.encode("t_list_2_3", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.decode("t_list_2_3", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.encode("t_list_2_3", self.L3a), self.L3a)
        self.assertDictEqual(self.tc.decode("t_list_2_3", self.L3a), self.L3a)

    def test_list_1_n_verbose(self):  # n-F, 0-F, 1-P, 2-P, 3-P
        self.tc.set_mode(True, True)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_1_n", self.Lna)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_1_n", self.Lna)
        with self.assertRaises(ValueError):
            self.tc.encode("t_list_1_n", self.L0a)
        with self.assertRaises(ValueError):
            self.tc.decode("t_list_1_n", self.L0a)
        self.assertDictEqual(self.tc.encode("t_list_1_n", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.decode("t_list_1_n", self.L1a), self.L1a)
        self.assertDictEqual(self.tc.encode("t_list_1_n", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.decode("t_list_1_n", self.L2a), self.L2a)
        self.assertDictEqual(self.tc.encode("t_list_1_n", self.L3a), self.L3a)
        self.assertDictEqual(self.tc.decode("t_list_1_n", self.L3a), self.L3a)
示例#26
0
 def setUp(self):
     jadn_check(schema_listfield)
     self.tc = Codec(schema_listfield)
 def setUp(self):
     schema = jadn_load(os.path.join("schema", "relax1.jadn"))
     self.tc = Codec(schema)
class OpenC2(unittest.TestCase):
    def setUp(self):
        schema = jadn_load(os.path.join("schema", "openc2.jadn"))
        self.tc = Codec(schema)

    def check(self, item, cmd_api, cmd_min, cmd_flat):
        self.tc.set_mode(False, False)  # Minified (list/tag)
        self.assertEqual(self.tc.encode(item, cmd_api), cmd_min)
        self.assertEqual(self.tc.decode(item, cmd_min), cmd_api)
        self.tc.set_mode(True, True)  # API / Verbose (dict/name)
        self.assertEqual(self.tc.encode(item, cmd_api), cmd_api)
        self.assertEqual(self.tc.decode(item, cmd_api), cmd_api)
        self.assertEqual(flatten(cmd_api), cmd_flat)
        self.assertEqual(fluff(cmd_flat), cmd_api)

    def test1_delete_cmd(self):
        cmd_api = {
            "action": "delete",
            "target": {
                "file": {
                    "name": "otaku.exe",
                    "hashes": {
                        "SHA-256":
                        "19ce084ab0599c1659e4ce12ae822bd3"
                        "02e494608d796b8b8a233fdfc8456663"
                    }
                }
            },
            "actuator": {
                "endpoint_workstation": {
                    "actuator_id": "dns://192.168.110.120",
                    "asset_id": "B4920J"
                }
            },
            "modifiers": {
                "command_id": "SEP1432_84295"
            }
        }

        cmd_flat = {
            "action": "delete",
            "target.file.name": "otaku.exe",
            "target.file.hashes.SHA-256": "19ce084ab0599c1659e4ce12ae822bd3"
            "02e494608d796b8b8a233fdfc8456663",
            "actuator.endpoint_workstation.actuator_id":
            "dns://192.168.110.120",
            "actuator.endpoint_workstation.asset_id": "B4920J",
            "modifiers.command_id": "SEP1432_84295"
        }

        cmd_min = [
            19, {
                "10": {
                    "2": {
                        "6":
                        "19ce084ab0599c1659e4ce12ae822bd302e494608d796b8b8a233fdfc8456663"
                    },
                    "4": "otaku.exe"
                }
            }, {
                "11": ["dns://192.168.110.120", "B4920J"]
            }, {
                "6": "SEP1432_84295"
            }
        ]

        self.check("OpenC2Command", cmd_api, cmd_min, cmd_flat)

    def test1_delete_response(self):
        cmd_api = {"status": "OK", "response_src": "dns://192.168.110.120"}
        cmd_flat = cmd_api
        cmd_min = [200, None, "dns://192.168.110.120"]

        self.check("OpenC2Response", cmd_api, cmd_min, cmd_flat)

    def test2_respond_cmd(self):
        cmd_api = {
            "action": "report",
            "target": {
                "url": "dummy"
            },
            "actuator": {
                "endpoint_workstation": {
                    "actuator_id": "dns://192.168.110.120"
                }
            },
            "modifiers": {
                "respond_to": "dns://remote-server14.example.com",
                "command_ref": "SEP1432_84295"
            }
        }

        cmd_flat = {
            "action": "report",
            "target.url": "dummy",
            "actuator.endpoint_workstation.actuator_id":
            "dns://192.168.110.120",
            "modifiers.respond_to": "dns://remote-server14.example.com",
            "modifiers.command_ref": "SEP1432_84295"
        }

        cmd_min = [
            4, {
                "18": "dummy"
            }, {
                "11": ["dns://192.168.110.120"]
            }, {
                "9": "dns://remote-server14.example.com",
                "17": "SEP1432_84295"
            }
        ]

        self.check("OpenC2Command", cmd_api, cmd_min, cmd_flat)