Skip to content

Commit 3a18006

Browse files
author
unknown
committed
Initial commit.
1 parent 6f2780a commit 3a18006

12 files changed

+768
-0
lines changed

Diff for: MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include LICENSE

Diff for: README

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
McAfee Threat Intelligence Exchange(TIE) DXL Python Client Library
2+
======================================================
3+
4+
Overview
5+
--------
6+
7+
8+
Documentation
9+
-------------
10+
11+
12+
Bugs and Feedback
13+
-----------------
14+
15+
For bugs, questions and discussions please use the `GitHub Issues <https://github.com/opendxl/opendxl-tie-client-python/issues>`_.
16+
17+
LICENSE
18+
-------
19+
20+
Copyright 2016 McAfee, Inc.
21+
22+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
23+
License. You may obtain a copy of the License at
24+
25+
`<http://www.apache.org/licenses/LICENSE-2.0>`_

Diff for: dxltieclient/__init__.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- coding: utf-8 -*-
2+
################################################################################
3+
# Copyright (c) 2016 McAfee Inc. - All Rights Reserved.
4+
################################################################################
5+
from __future__ import absolute_import
6+
7+
from .client import TieClient
8+
from .constants import *
9+
10+
__version__ = "0.1.0"
11+
12+
13+
def get_version():
14+
"""
15+
Returns the version of the McAfee Threat Intelligence Exchange(TIE) DXL Client library
16+
17+
:return: The version of the McAfee Threat Intelligence Exchange(TIE) DXL Client library
18+
"""
19+
return __version__

Diff for: dxltieclient/client.py

+244
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# -*- coding: utf-8 -*-
2+
################################################################################
3+
# Copyright (c) 2016 McAfee Inc. - All Rights Reserved.
4+
################################################################################
5+
6+
import base64
7+
import json
8+
import logging
9+
from dxlclient import Request, Message
10+
from constants import *
11+
12+
# TIE File Reputation Topics
13+
TIE_SET_FILE_REPUTATION_TOPIC = "/mcafee/service/tie/file/reputation/set"
14+
TIE_GET_FILE_REPUTATION_TOPIC = "/mcafee/service/tie/file/reputation"
15+
16+
# TIE Certificate Reputation Topics
17+
TIE_SET_CERT_REPUTATION_TOPIC = "/mcafee/service/tie/cert/reputation/set"
18+
TIE_GET_CERT_REPUTATION_TOPIC = "/mcafee/service/tie/cert/reputation"
19+
20+
# TIE file first reference topic
21+
TIE_GET_FILE_FIRST_REFS = "/mcafee/service/tie/file/agents"
22+
23+
# TIE event topics
24+
TIE_EVENT_FILE_DETECTION_TOPIC = "/mcafee/event/tie/file/detection"
25+
TIE_EVENT_FILE_REPUTATION_CHANGE_TOPIC = "/mcafee/event/tie/file/repchange/broadcast"
26+
TIE_EVENT_FILE_FIRST_INSTANCE_TOPIC = "/mcafee/event/tie/file/firstinstance"
27+
TIE_EVENT_FILE_PREVALENCE_CHANGE_TOPIC = "/mcafee/event/tie/file/prevalence"
28+
TIE_EVENT_CERTIFICATE_REPUTATION_CHANGE_TOPIC = "/mcafee/event/tie/cert/repchange/broadcast"
29+
30+
class TieClient(object):
31+
"""
32+
This client provides a high level wrapper for communicating with the
33+
McAfee Threat Intelligence Echange(TIE) DXL service.
34+
35+
The purpose of this client is to allow the user to perform TIE queries without having to focus on
36+
lower-level details such as TIE-specific DXL topics and message formats.
37+
"""
38+
39+
# The default amount of time (in seconds) to wait for a response from the TIE server
40+
__DEFAULT_RESPONSE_TIMEOUT = 30
41+
# The minimum amount of time (in seconds) to wait for a response from the TIE server
42+
__MIN_RESPONSE_TIMEOUT = 30
43+
44+
def __init__(self, dxl_client):
45+
"""
46+
Constructs the Threat Intelligence Exchange client
47+
48+
:param dxl_client: The DXL client to use for communication with the TIE service
49+
"""
50+
self.__dxl_client = dxl_client
51+
self.__response_timeout = self.__DEFAULT_RESPONSE_TIMEOUT
52+
53+
@property
54+
def response_timeout(self):
55+
"""
56+
The maximum amount of time (in seconds) to wait for a response from the TIE server
57+
"""
58+
return self.__response_timeout
59+
60+
@response_timeout.setter
61+
def response_timeout(self, response_timeout):
62+
if response_timeout < self.__MIN_RESPONSE_TIMEOUT:
63+
raise Exception("Response timeout must be greater than or equal to " + str(self.__MIN_RESPONSE_TIMEOUT))
64+
self.__response_timeout = response_timeout
65+
66+
def set_file_reputation(self, hashes, reputation_level, filename="", comment="",
67+
provider_id=FILE_ENTERPRISE_PROVIDER):
68+
"""
69+
Sets the reputation for the specified file
70+
71+
:param hashes: A dictionary of the hashes identifying this file
72+
:param reputation_level: The reputation level of the file
73+
:param filename: A filename to set for association with this file
74+
:param comment: A comment for this reputation change
75+
:param provider_id: The provider ID for this file
76+
"""
77+
# Create the request message
78+
req = Request(TIE_SET_FILE_REPUTATION_TOPIC)
79+
80+
# Create a dictionary for the payload
81+
payload_dict = {
82+
"trustLevel": reputation_level,
83+
"providerId": provider_id,
84+
"filename": filename,
85+
"comment": comment,
86+
"hashes": []}
87+
88+
for key, value in hashes.items():
89+
payload_dict["hashes"].append({"type": key, "value": base64.b64encode(value.decode('hex'))})
90+
91+
# Set the payload
92+
req.payload = json.dumps(payload_dict).encode()
93+
94+
# Send the request
95+
self.__dxl_sync_request(req)
96+
97+
def get_file_reputation(self, hashes):
98+
"""
99+
Gets the TIE reputations for the specified file
100+
101+
:param hashes: A dictionary of the hashes identifying this file
102+
:return: A dictionary of provider ID to reputation
103+
"""
104+
# Create the request message
105+
req = Request(TIE_GET_FILE_REPUTATION_TOPIC)
106+
107+
# Create a dictionary for the payload
108+
payload_dict = {"hashes": []}
109+
110+
for key, value in hashes.items():
111+
payload_dict["hashes"].append({"type": key, "value": base64.b64encode(value.decode('hex'))})
112+
113+
# Set the payload
114+
req.payload = json.dumps(payload_dict).encode()
115+
116+
# Send the request
117+
response = self.__dxl_sync_request(req)
118+
119+
resp_dict = json.loads(response.payload.decode())
120+
121+
# Return the reputations list
122+
if "reputations" in resp_dict:
123+
reputation_dict = {}
124+
for reputation in resp_dict["reputations"]:
125+
reputation_dict[reputation[PROVIDER_ID]] = reputation
126+
return reputation_dict
127+
else:
128+
return {}
129+
130+
def set_certificate_reputation(self, sha1, public_key_sha1, reputation_level, comment="",
131+
provider_id=CERTIFICATE_ENTERPRISE_PROVIDER):
132+
"""
133+
Sets the reputation for the specified certificate
134+
135+
:param sha1: The SHA1 of the certificate body
136+
:param public_key_sha1: The SHA1 of the certificate's public key
137+
:param reputation_level: The reputation level of the certificate
138+
:param comment: A comment for this reputation change
139+
:param provider_id: The provider ID to set this reputation as
140+
"""
141+
# Create the request message
142+
req = Request(TIE_SET_CERT_REPUTATION_TOPIC)
143+
144+
# Create a dictionary for the payload
145+
payload_dict = {
146+
"trustLevel": reputation_level,
147+
"providerId": provider_id,
148+
"publicKeySha1": base64.b64encode(public_key_sha1.decode('hex')),
149+
"comment": comment,
150+
"hashes": [
151+
{"type": "sha1", "value": base64.b64encode(sha1.decode('hex'))}
152+
]}
153+
154+
# Set the payload
155+
req.payload = json.dumps(payload_dict).encode()
156+
157+
# Send the request
158+
self.__dxl_sync_request(req)
159+
160+
def get_certificate_reputation(self, sha1, public_key_sha1):
161+
"""
162+
Gets the reputation for the specified certificate
163+
164+
:param sha1: The SHA1 of the certificate body
165+
:param public_key_sha1: The SHA1 of the certificate's public key
166+
:return: A dictionary of provider ID to reputation
167+
"""
168+
# Create the request message
169+
req = Request(TIE_GET_CERT_REPUTATION_TOPIC)
170+
171+
# Create a dictionary for the payload
172+
payload_dict = {
173+
"publicKeySha1": base64.b64encode(public_key_sha1.decode('hex')),
174+
"hashes": [
175+
{"type": "sha1", "value": base64.b64encode(sha1.decode('hex'))}
176+
]}
177+
178+
# Set the payload
179+
req.payload = json.dumps(payload_dict).encode()
180+
181+
# Send the request
182+
response = self.__dxl_sync_request(req)
183+
184+
resp_dict = json.loads(response.payload.decode())
185+
186+
# Return the reputations list
187+
if "reputations" in resp_dict:
188+
reputation_dict = {}
189+
for reputation in resp_dict["reputations"]:
190+
reputation_dict[reputation[PROVIDER_ID]] = reputation
191+
return reputation_dict
192+
else:
193+
return []
194+
195+
def get_file_first_references(self, hashes, query_limit=500):
196+
"""
197+
Gets the agents which have run the specified file
198+
199+
:param hashes: A dictionary of the hashes for the file to search by
200+
:param query_limit: The maximum number of results to return
201+
:return: A list of agent dictionary items
202+
"""
203+
# Create the request message
204+
req = Request(TIE_GET_FILE_FIRST_REFS)
205+
206+
# Create a dictionary for the payload
207+
payload_dict = {
208+
"queryLimit": query_limit,
209+
"hashes": []
210+
}
211+
212+
for key, value in hashes.items():
213+
payload_dict["hashes"].append({"type": key, "value": base64.b64encode(value.decode('hex'))})
214+
215+
# Set the payload
216+
req.payload = json.dumps(payload_dict).encode()
217+
218+
# Send the request
219+
response = self.__dxl_sync_request(req)
220+
221+
resp_dict = json.loads(response.payload.decode())
222+
223+
# Return the agents list
224+
if "agents" in resp_dict:
225+
return resp_dict["agents"]
226+
else:
227+
return []
228+
229+
230+
def __dxl_sync_request(self, request):
231+
"""
232+
Performs a synchronous DXL request. Throws an exception if an error occurs
233+
234+
:param request: The request to send
235+
:return: The DXL response
236+
"""
237+
# Send the request and wait for a response (synchronous)
238+
res = self.__dxl_client.sync_request(request, timeout=self.__response_timeout)
239+
240+
# Return a dictionary corresponding to the response payload
241+
if res.message_type != Message.MESSAGE_TYPE_ERROR:
242+
return res
243+
else:
244+
raise Exception("Error: " + res.error_message + " (" + str(res.error_code) + ")")

0 commit comments

Comments
 (0)