summaryrefslogtreecommitdiffstats
path: root/test/functional/util
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtest/functional/util/dummy_avast.py53
-rwxr-xr-xtest/functional/util/dummy_clam.py50
-rwxr-xr-xtest/functional/util/dummy_fprot.py54
-rwxr-xr-xtest/functional/util/dummy_http.py145
-rw-r--r--test/functional/util/dummy_killer.py30
-rwxr-xr-xtest/functional/util/dummy_p0f.py98
-rwxr-xr-xtest/functional/util/dummy_ssl.py66
-rwxr-xr-xtest/functional/util/dummy_udp.py26
-rw-r--r--test/functional/util/nn_unpack.lua16
-rw-r--r--test/functional/util/server.pem46
10 files changed, 584 insertions, 0 deletions
diff --git a/test/functional/util/dummy_avast.py b/test/functional/util/dummy_avast.py
new file mode 100755
index 0000000..a4a6c62
--- /dev/null
+++ b/test/functional/util/dummy_avast.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+
+PID = "/tmp/dummy_avast.pid"
+
+import os
+import socket
+import socketserver
+import sys
+
+import dummy_killer
+
+class MyTCPHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ self.request.sendall(b"220 DAEMON\r\n")
+ self.data = self.request.recv(1024).strip()
+ self.request.sendall(b"210 SCAN DATA\r\n")
+ if self.server.foundvirus:
+ self.request.sendall(b"SCAN /some/path/malware/xpaj/00908235ee9e267fa2f4c83fb4304c63af976cbc\t[L]0.0\t0 Eicar\\ [Heur]\r\n")
+ else:
+ self.request.sendall(b"SCAN /some/path/malware/xpaj/00908235ee9e267fa2f4c83fb4304c63af976cbc\t[+]\r\n")
+ self.request.sendall(b"200 SCAN OK\r\n")
+ self.request.close()
+
+if __name__ == "__main__":
+ HOST = "localhost"
+
+ alen = len(sys.argv)
+ if alen > 1:
+ port = int(sys.argv[1])
+ if alen >= 3:
+ foundvirus = bool(sys.argv[2])
+ else:
+ foundvirus = False
+ else:
+ port = 3310
+ foundvirus = False
+
+ server = socketserver.TCPServer((HOST, port), MyTCPHandler, bind_and_activate=False)
+ server.allow_reuse_address = True
+ server.foundvirus = foundvirus
+ server.server_bind()
+ server.server_activate()
+
+ dummy_killer.setup_killer(server)
+ dummy_killer.write_pid(PID)
+
+ try:
+ server.handle_request()
+ except socket.error:
+ print("Socket closed")
+
+ server.server_close()
diff --git a/test/functional/util/dummy_clam.py b/test/functional/util/dummy_clam.py
new file mode 100755
index 0000000..1b614f5
--- /dev/null
+++ b/test/functional/util/dummy_clam.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+
+PID = "/tmp/dummy_clamav.pid"
+
+import os
+import socket
+import socketserver
+import sys
+
+import dummy_killer
+
+class MyTCPHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ self.data = self.request.recv(1024).strip()
+ if self.server.foundvirus:
+ self.request.sendall(b"stream: Eicar-Test-Signature FOUND\0")
+ else:
+ self.request.sendall(b"stream: OK\0")
+ self.request.close()
+
+if __name__ == "__main__":
+ HOST = "localhost"
+
+ alen = len(sys.argv)
+ if alen > 1:
+ port = int(sys.argv[1])
+ if alen >= 3:
+ foundvirus = bool(sys.argv[2])
+ else:
+ foundvirus = False
+ else:
+ port = 3310
+ foundvirus = False
+
+ server = socketserver.TCPServer((HOST, port), MyTCPHandler, bind_and_activate=False)
+ server.allow_reuse_address = True
+ server.foundvirus = foundvirus
+ server.server_bind()
+ server.server_activate()
+
+ dummy_killer.setup_killer(server)
+ dummy_killer.write_pid(PID)
+
+ try:
+ server.handle_request()
+ except socket.error:
+ print("Socket closed")
+
+ server.server_close()
diff --git a/test/functional/util/dummy_fprot.py b/test/functional/util/dummy_fprot.py
new file mode 100755
index 0000000..31ae2c4
--- /dev/null
+++ b/test/functional/util/dummy_fprot.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+
+import os
+import signal
+import socket
+import socketserver
+import sys
+
+import dummy_killer
+
+PID = "/tmp/dummy_fprot.pid"
+
+class MyTCPHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ self.data = self.request.recv(1024).strip()
+ if self.server.foundvirus:
+ self.request.sendall(b"1 <infected: EICAR_Test_File> FOO->bar\n")
+ else:
+ self.request.sendall(b"0 <clean> FOO\n")
+ self.request.close()
+
+if __name__ == "__main__":
+
+ HOST = "localhost"
+
+ alen = len(sys.argv)
+ if alen > 1:
+ port = int(sys.argv[1])
+ if alen >= 4:
+ PID = sys.argv[3]
+ foundvirus = bool(sys.argv[2])
+ elif alen >= 3:
+ foundvirus = bool(sys.argv[2])
+ else:
+ foundvirus = False
+ else:
+ port = 10200
+ foundvirus = False
+
+ server = socketserver.TCPServer((HOST, port), MyTCPHandler, bind_and_activate=False)
+ server.allow_reuse_address = True
+ server.foundvirus = foundvirus
+ server.server_bind()
+ server.server_activate()
+
+ dummy_killer.setup_killer(server)
+ dummy_killer.write_pid(PID)
+
+ try:
+ server.handle_request()
+ except socket.error:
+ print("Socket closed")
+ server.server_close()
diff --git a/test/functional/util/dummy_http.py b/test/functional/util/dummy_http.py
new file mode 100755
index 0000000..c1abf7e
--- /dev/null
+++ b/test/functional/util/dummy_http.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+
+import asyncio
+import dummy_killer
+import tornado.ioloop
+import tornado.web
+import tornado.httpserver
+import ssl
+import argparse
+import os
+
+class MainHandler(tornado.web.RequestHandler):
+ @tornado.gen.coroutine
+ def get(self, path):
+ if path == '/empty':
+ # Return an empty reply
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/error_403':
+ # Return a 403 HTTP error
+ raise tornado.web.HTTPError(403)
+ elif path == '/timeout':
+ # Wait for 4 seconds before returning an empty reply
+ yield tornado.gen.sleep(4)
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/request':
+ # Return a string 'hello world'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hello world")
+ elif path == '/map-simple':
+ # Return a string 'hello map'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hello map")
+ elif path == '/map-query':
+ # Parse the 'key' argument from the HTTP request
+ key = self.get_query_argument("key", default=None)
+ if key == 'au':
+ # Return a string 'hit' if 'key' is equal to 'au'
+ self.set_header("Content-Type", "text/plain")
+ self.write("1.0")
+ else:
+ # Return a 404 HTTP error if 'key' is not equal to 'au'
+ raise tornado.web.HTTPError(404)
+ elif path == '/settings':
+ self.set_header("Content-Type", "application/json")
+ self.write("{\"actions\": { \"reject\": 1.0}, \"symbols\": { \"EXTERNAL_SETTINGS\": 1.0 }}")
+ else:
+ raise tornado.web.HTTPError(404)
+
+ @tornado.gen.coroutine
+ def post(self, path):
+ if path == '/empty':
+ # Return an empty reply
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/error_403':
+ # Return a 403 HTTP error
+ raise tornado.web.HTTPError(403)
+ elif path == '/request':
+ # Return a string 'hello post'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hello post")
+ elif path == '/timeout':
+ # Wait for 4 seconds before returning an empty reply
+ yield tornado.gen.sleep(4)
+ self.set_header("Content-Type", "text/plain")
+ self.write("")
+ elif path == '/map-simple':
+ # Return a string 'hello map'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hello map")
+ elif path == '/map-query':
+ # Parse the 'key' argument from the HTTP request
+ key = self.get_query_argument("key", default="")
+ if key == 'au':
+ # Return a string 'hit' if 'key' is equal to 'au'
+ self.set_header("Content-Type", "text/plain")
+ self.write("hit")
+ else:
+ # Return a 404 HTTP error if 'key' is not equal to 'au'
+ raise tornado.web.HTTPError(404)
+ elif path == '/settings':
+ self.set_header("Content-Type", "application/json")
+ self.write("{\"actions\": { \"reject\": 1.0}, \"symbols\": { \"EXTERNAL_SETTINGS\": 1.0 }}")
+ else:
+ raise tornado.web.HTTPError(404)
+
+ def head(self, path):
+ self.set_header("Content-Type", "text/plain")
+ if path == "/redirect1":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"{self.request.protocol}://{self.request.host}/hello")
+ elif path == "/redirect2":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"{self.request.protocol}://{self.request.host}/redirect1")
+ elif self.path == "/redirect3":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"{self.request.protocol}://{self.request.host}/redirect4")
+ elif self.path == "/redirect4":
+ # Send an HTTP redirect to the bind address of the server
+ self.redirect(f"{self.request.protocol}://{self.request.host}/redirect3")
+ else:
+ self.send_response(200)
+ self.set_header("Content-Type", "text/plain")
+
+def make_app():
+ return tornado.web.Application([
+ (r"(/[^/]+)", MainHandler),
+ ])
+
+async def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--bind", "-b", default="localhost", help="bind address")
+ parser.add_argument("--port", "-p", type=int, default=18080, help="bind port")
+ parser.add_argument("--keyfile", "-k", help="server private key file")
+ parser.add_argument("--certfile", "-c", help="server certificate file")
+ parser.add_argument("--pidfile", "-pf", help="path to the PID file")
+ args = parser.parse_args()
+
+ # Create the Tornado application
+ app = make_app()
+
+ # If keyfile and certfile are provided, create an HTTPS server.
+ # Otherwise, create an HTTP server.
+ if args.keyfile and args.certfile:
+ ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+ ssl_ctx.load_cert_chain(args.certfile, args.keyfile)
+ server = tornado.httpserver.HTTPServer(app, ssl_options=ssl_ctx)
+ else:
+ server = tornado.httpserver.HTTPServer(app)
+
+ # Write the PID to the specified PID file, if provided
+ if args.pidfile:
+ dummy_killer.write_pid(args.pidfile)
+
+ # Start the server
+ server.bind(args.port, args.bind)
+ server.start(1)
+
+ await asyncio.Event().wait()
+
+if __name__ == "__main__":
+ loop = asyncio.get_event_loop()
+ loop.run_until_complete(main())
diff --git a/test/functional/util/dummy_killer.py b/test/functional/util/dummy_killer.py
new file mode 100644
index 0000000..0a052fb
--- /dev/null
+++ b/test/functional/util/dummy_killer.py
@@ -0,0 +1,30 @@
+import signal
+import os
+import atexit
+import tempfile
+
+def setup_killer(server, method = None):
+ def default_method():
+ server.server_close()
+
+ if method is None:
+ method = default_method
+
+ def alarm_handler(signum, frame):
+ method()
+
+ signal.signal(signal.SIGALRM, alarm_handler)
+ signal.signal(signal.SIGTERM, alarm_handler)
+ signal.alarm(120)
+
+
+def write_pid(path):
+ with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
+ f.write(str(os.getpid()))
+ f.close()
+ os.rename(f.name, path)
+
+ def cleanup():
+ os.remove(path)
+
+ atexit.register(cleanup)
diff --git a/test/functional/util/dummy_p0f.py b/test/functional/util/dummy_p0f.py
new file mode 100755
index 0000000..1d86ba0
--- /dev/null
+++ b/test/functional/util/dummy_p0f.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+
+PID = "/tmp/dummy_p0f.pid"
+
+import os
+import sys
+import struct
+import socket
+import socketserver
+
+import dummy_killer
+
+class MyStreamHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ S = {
+ 'bad_query' : 0x0,
+ 'ok' : 0x10,
+ 'no_match' : 0x20
+ }
+
+ OS = {
+ 'windows' : (b'Windows', b'7 or 8'),
+ 'linux' : (b'Linux', b'3.11 and newer')
+ }
+
+ self.data = self.request.recv(21).strip()
+
+ if self.server.p0f_status == 'bad_response':
+ response = 0
+ else:
+ response = struct.pack(
+ "IbIIIIIIIhbb32s32s32s32s32s32s",
+ 0x50304602, # magic
+ S[self.server.p0f_status], # status
+ 1568493408, # first_seen
+ 1568493408, # last_seen
+ 1, # total_conn
+ 1, # uptime_min
+ 4, # up_mod_days
+ 1568493408, # last_nat
+ 1568493408, # last_chg
+ 10, # distance
+ 0, # bad_sw
+ 0, # os_match_q
+ OS[self.server.p0f_os][0], # os_name
+ OS[self.server.p0f_os][1], # os_flavor
+ b'', # http_name
+ b'', # http_flavor
+ b'Ethernet or modem', # link_type
+ b'' # language
+ )
+
+ self.request.sendall(response)
+ self.request.close()
+
+def cleanup(SOCK):
+ if os.path.exists(SOCK):
+ try:
+ os.unlink(SOCK)
+ except OSError:
+ print("Could not unlink socket: " + SOCK)
+
+if __name__ == "__main__":
+ SOCK = '/tmp/p0f.sock'
+ p0f_status = 'ok'
+ p0f_os = 'linux'
+
+ os.umask(0000)
+
+ alen = len(sys.argv)
+ if alen > 1:
+ SOCK = sys.argv[1]
+ if alen >= 4:
+ p0f_os = sys.argv[2]
+ p0f_status = sys.argv[3]
+ elif alen >= 3:
+ p0f_os = sys.argv[2]
+
+ cleanup(SOCK)
+
+ server = socketserver.UnixStreamServer(SOCK, MyStreamHandler, bind_and_activate=False)
+ server.allow_reuse_address = True
+ server.p0f_status = p0f_status
+ server.p0f_os = p0f_os
+ server.server_bind()
+ server.server_activate()
+
+ dummy_killer.setup_killer(server)
+ dummy_killer.write_pid(PID)
+
+ try:
+ server.handle_request()
+ except socket.error:
+ print("Socket closed")
+
+ server.server_close()
+ cleanup(SOCK)
diff --git a/test/functional/util/dummy_ssl.py b/test/functional/util/dummy_ssl.py
new file mode 100755
index 0000000..44b1782
--- /dev/null
+++ b/test/functional/util/dummy_ssl.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+import os
+import socket
+import ssl
+import sys
+import time
+
+import dummy_killer
+import socketserver
+
+PORT = 14433
+HOST_NAME = '127.0.0.1'
+
+PID = "/tmp/dummy_ssl.pid"
+
+class SSLTCPHandler(socketserver.StreamRequestHandler):
+ def handle(self):
+ time.sleep(0.5)
+ data = self.request.recv(6000000)
+ while data:
+ print("{} wrote:".format(self.client_address[0]))
+ print(data)
+ time.sleep(0.1)
+ self.request.sendall(b'hello\n')
+ time.sleep(0.1)
+ data = self.request.recv(6000000)
+
+class SSL_TCP_Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
+ def __init__(self,
+ server_address,
+ RequestHandlerClass,
+ certfile,
+ keyfile,
+ bind_and_activate=True):
+ self.allow_reuse_address = True
+ super().__init__(server_address, RequestHandlerClass, False)
+ self.timeout = 1
+ ctx = ssl.create_default_context()
+ ctx.load_cert_chain(certfile=certfile)
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
+ self.socket = ctx.wrap_socket(self.socket, server_side=True)
+ if (bind_and_activate):
+ self.server_bind()
+ self.server_activate()
+
+ def run(self):
+ dummy_killer.write_pid(PID)
+ try:
+ self.serve_forever()
+ except KeyboardInterrupt:
+ print("Interrupt")
+ except socket.error as e:
+ print("Socket closed {}".format(e))
+ finally:
+ self.server_close()
+
+ def stop(self):
+ self.keep_running = False
+ self.server_close()
+
+if __name__ == '__main__':
+ server = SSL_TCP_Server((HOST_NAME, PORT), SSLTCPHandler, sys.argv[1], sys.argv[1])
+ dummy_killer.setup_killer(server, server.stop)
+ server.run()
diff --git a/test/functional/util/dummy_udp.py b/test/functional/util/dummy_udp.py
new file mode 100755
index 0000000..f05d6d6
--- /dev/null
+++ b/test/functional/util/dummy_udp.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+import socket
+import sys
+
+import dummy_killer
+
+UDP_IP = "127.0.0.1"
+PID = "/tmp/dummy_udp.pid"
+
+if __name__ == "__main__":
+ alen = len(sys.argv)
+ if alen > 1:
+ port = int(sys.argv[1])
+ else:
+ port = 5005
+ sock = socket.socket(socket.AF_INET, # Internet
+ socket.SOCK_DGRAM) # UDP
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind((UDP_IP, port))
+ dummy_killer.write_pid(PID)
+
+ while True:
+ data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
+ print("received message:", data)
+ sock.sendto(data, addr)
diff --git a/test/functional/util/nn_unpack.lua b/test/functional/util/nn_unpack.lua
new file mode 100644
index 0000000..fee98d5
--- /dev/null
+++ b/test/functional/util/nn_unpack.lua
@@ -0,0 +1,16 @@
+local ucl = require "ucl"
+
+local function unhex(str)
+ return (str:gsub('..', function (cc)
+ return string.char(tonumber(cc, 16))
+ end))
+end
+
+local parser = ucl.parser()
+local ok, err = parser:parse_string(unhex(arg[1]), 'msgpack')
+if not ok then
+ io.stderr:write(err)
+ os.exit(1)
+end
+
+print(ucl.to_format(parser:get_object(), 'json-compact'))
diff --git a/test/functional/util/server.pem b/test/functional/util/server.pem
new file mode 100644
index 0000000..b5ec4c3
--- /dev/null
+++ b/test/functional/util/server.pem
@@ -0,0 +1,46 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA1nROqQC9tDLdnC2o1246g1T/oDq5Szbktof7TPHm/wDmWG47
+pwD22UkyEXthlq9kT9BZEgN6E2XF9UeA/7tZw7S4nbDUY/gWoGu7KlGLIIb5YXBW
+CzSHAwlJtW/Pg5Muk7vJldHOufBJXP99PjJVzZZuYvv9+JJfSWHEeuY+RysWnTX5
+saq4cwDG8fCKqKEwy8PKatr8eJFL1/cPnC/0SAB77mIEdYHV5hBDUoNTpPWQrB2s
+SgTqLa2pYTCWGUAvu4TiZKx00f6Z7soLa8RXddhEj6Qu5zLl+t5Llc8iSr7MgWTZ
+0PD/lChOUg7H9STM4KiQ/qtBvSyGB0Cz71aWdQIDAQABAoIBAQDVAuG+7IWBn6SP
+pKq4kTx9hsgCF1JFa1jyFU9/tieD0xj5bUTDNSn72cBprOvaCIzS2lgelGWFLuna
+IBP579XRlohp2WKdiaav4VIfTq+qt2atai+NIbeZRHh6R30Pa/ovs68fqS51cj7s
+qLl2NfkUI/+xQiuZ44nSEdJfYKMre8d/sF2zWg5sO5DaJWYsKdAqclRR4q8ZrEQY
+6AZ8hsAlsyczpvU1A7Y/XWnyg7jr2towxeAbey13phFdukrZnRq2pRaprvwA1KqC
+AtO0jx7L3MP3eamwQaNyaBD/PE+wnGpbPr36oU1ewhUTSZUlx3aYzaUDPrqMWwMk
+7cb/gnsBAoGBAO9OQCnVE4D8r3DCRtmFfgqasWIakEs591+lzVSnHrLDsiaPk/5Q
+Rv6FAyxU8T78SJNaYgCH3XW0NHeyyNi3Z1TQ9HDZLuiAhrVptIWFSvjCGIE4ijCG
+3JQLkKPs2d/5/fXcZbgNhcm0lLYtP3SOsVB2p75dER8BjVVSsl14UfUJAoGBAOVq
+PNSI55/jgwaA/zvX+fsawY6V20C42KpDq7LywAk/JCf5+pHZX4szClj3CS3shdP3
+B7WRqNHfLHTF7ID+JYpkahJI/Zq6a5wR4i/zXLIQCtSIaR0zZcDBu9GZvcwQlnLR
+wvkkOlHXlmkmq94FV/i/b2rmbK7RTuc2TGk5+j0NAoGAGmZpkbPeCPbXa/si0dB2
+TTkvpIEFtibY8YZbFqGxM0t/ld11GDNHAcEuzm84hhhS8V6hPSm/9sJAn4vruGzT
+S3oZ3XE4SZIUSmM09R31XWgcR/Uy2ZOnNfXoqQzyJFFyAPOljR6AyfXQCiEHxRYQ
+3a2ZZ9jgkKkdLHKJFuK1N/ECgYAcdoDTkaTDJpQEA48nGpWuPNSU3yzTq9tdzIWJ
+7yo6O3Y963rWC5UaDRwUi5m88+JquPRg55B9cWXvmvrLyjxYHjs2x42HW+er9mAM
+uPHgObNOSRpZgB34u1CVIbD1l31DA5lgFcmSi9/ibeTW5+zRNNca+Tm0us1CTG9Q
+gtv0JQKBgQCdqEhX8h10N4qQQ/E0ejX5VSR6JE/EfbFO2gaL62YOhSRKaddZvG7R
+npQeNY2yS1TIoU/LT5pC5ytQ6hwjWFLo98MHY6B0rUWbUl8Uzsz+mcKbVSZnEIWj
+9CGVOzPlLELRJdTqVUNPdJu7NjzNKoizZjAU1SynHFu7jy98e730QA==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDGDCCAgACCQCoEpIa1RdPlzANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJh
+YTELMAkGA1UECAwCYWExCzAJBgNVBAcMAmFhMQswCQYDVQQKDAJhYTELMAkGA1UE
+CwwCYWExCzAJBgNVBAMMAmFhMB4XDTE5MDUyOTIxMTMzNFoXDTE5MDYyODIxMTMz
+NFowTjELMAkGA1UEBhMCYWExCzAJBgNVBAgMAmFhMQswCQYDVQQHDAJhYTELMAkG
+A1UECgwCYWExCzAJBgNVBAsMAmFhMQswCQYDVQQDDAJhYTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANZ0TqkAvbQy3ZwtqNduOoNU/6A6uUs25LaH+0zx
+5v8A5lhuO6cA9tlJMhF7YZavZE/QWRIDehNlxfVHgP+7WcO0uJ2w1GP4FqBruypR
+iyCG+WFwVgs0hwMJSbVvz4OTLpO7yZXRzrnwSVz/fT4yVc2WbmL7/fiSX0lhxHrm
+PkcrFp01+bGquHMAxvHwiqihMMvDymra/HiRS9f3D5wv9EgAe+5iBHWB1eYQQ1KD
+U6T1kKwdrEoE6i2tqWEwlhlAL7uE4mSsdNH+me7KC2vEV3XYRI+kLucy5freS5XP
+Ikq+zIFk2dDw/5QoTlIOx/UkzOCokP6rQb0shgdAs+9WlnUCAwEAATANBgkqhkiG
+9w0BAQsFAAOCAQEAF0TDCTa239+aQikOsqPjhZL9+6W/2z84uzskpTs449P9sJ9a
+l6NcS0RnMmrhkUS/XdesFUOqabH2hMrj7rr8ezH6Y9GMT84ncvUaZAhFy1k5wwyB
+E2hUJ6rv66VNWQ4I4Uxc9xoiqkAk4waFXhFiQZfVJ91RwLzXMJPsgAV9Wspg/jk8
+dNP1MW0rGrUx8CodkT370chI7DYHFTVudeb+MLUIF1RHQ4p/ATvzWIex3sIpkllv
+BjUz5pvTiSy7PZGIHZdZh5n4JfFjrUJHGlWRulPhX5sw8XPn1bMRDr/9EKJDcsWS
+rx5ZUoYjrLdTA2XJMcQ2AYrIZLyyD5+ihN841g==
+-----END CERTIFICATE-----