From a6002cf71c7eab7c8e2aa4f1bca1bd171cd5af4b Mon Sep 17 00:00:00 2001 From: thomasv Date: Mon, 30 Sep 2013 14:01:49 +0200 Subject: [PATCH] SSL certificate validation --- lib/interface.py | 63 ++++++++++++++++++++++++++++++++++++++++++------ lib/network.py | 2 +- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/lib/interface.py b/lib/interface.py index 3c72098c8..713ea5099 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -17,8 +17,9 @@ # along with this program. If not, see . -import random, socket, ast, re, ssl, errno +import random, socket, ast, re, ssl, errno, os import threading, traceback, sys, time, json, Queue +import socks from version import ELECTRUM_VERSION, PROTOCOL_VERSION from util import print_error, print_msg @@ -147,7 +148,6 @@ class Interface(threading.Thread): print_error( "send_http", messages ) if self.proxy: - import socks socks.setdefaultproxy(proxy_modes.index(self.proxy["mode"]) + 1, self.proxy["host"], int(self.proxy["port"]) ) socks.wrapmodule(urllib2) @@ -210,36 +210,74 @@ class Interface(threading.Thread): def init_tcp(self, host, port, proxy=None, use_ssl=True): + + if self.use_ssl: + cert_path = os.path.join( self.config.get('path'), 'certs', host) + if not os.path.exists(cert_path): + dir_path = os.path.join( self.config.get('path'), 'certs') + if not os.path.exists(dir_path): + os.mkdir(dir_path) + try: + cert = ssl.get_server_certificate((host, port)) + except: + print_error("failed to connect", host, port) + return + + with open(cert_path,"w") as f: + f.write(cert) + self.init_server(host, port, proxy, use_ssl) global proxy_modes self.connection_msg = "%s:%d"%(self.host,self.port) + if self.proxy is None: s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) else: self.connection_msg += " using proxy %s:%s:%s"%(self.proxy.get('mode'), self.proxy.get('host'), self.proxy.get('port')) - import socks s = socks.socksocket() s.setproxy(proxy_modes.index(self.proxy["mode"]) + 1, self.proxy["host"], int(self.proxy["port"]) ) + if self.use_ssl: - s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, do_handshake_on_connect=True) - + try: + s = ssl.wrap_socket(s, + ssl_version=ssl.PROTOCOL_SSLv3, + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=cert_path, + do_handshake_on_connect=True) + except: + print_error("wrap_socket failed", host) + return + s.settimeout(2) s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) try: s.connect(( self.host.encode('ascii'), int(self.port))) + except ssl.SSLError, e: + print_error("SSL error:", host, e) + return except: #traceback.print_exc(file=sys.stdout) print_error("failed to connect", host, port) - self.is_connected = False - self.s = None return + # hostname verification (disabled) + if self.use_ssl and False: + from backports.ssl_match_hostname import match_hostname, CertificateError + try: + match_hostname(s.getpeercert(), host) + print_error("hostname matches", host) + except CertificateError, ce: + print_error("hostname does not match", host, s.getpeercert()) + return + s.settimeout(60) self.s = s self.is_connected = True + print_error("connected to", host, port) + def run_tcp(self): try: @@ -479,3 +517,14 @@ class Interface(threading.Thread): #print "change status", self.server, self.is_connected self.queue.put(self) + + +if __name__ == "__main__": + + q = Queue.Queue() + i = Interface({'server':'btc.it-zone.org:50002:s', 'path':'/extra/key/wallet', 'verbose':True}) + i.start(q) + time.sleep(1) + exit() + + diff --git a/lib/network.py b/lib/network.py index fd92faa08..d14a8ef96 100644 --- a/lib/network.py +++ b/lib/network.py @@ -95,7 +95,7 @@ class Network(threading.Thread): def start_interface(self, server): if server in self.interfaces.keys(): return - i = interface.Interface({'server':server}) + i = interface.Interface({'server':server, 'path':self.config.path}) self.interfaces[server] = i i.start(self.queue)