startTLS: enabled on server and client, TCP stays as default

This commit is contained in:
Alberto Sottile 2019-02-04 15:34:35 +01:00
parent 0890db8364
commit 58ccca5766
6 changed files with 44 additions and 77 deletions

3
.gitignore vendored
View File

@ -5,6 +5,7 @@ venv
/SyncPlay.egg-info
/build
/cert
/dist
/syncplay v*
/syncplay_v*
@ -13,4 +14,4 @@ dist.7z
.*
!.travis.yml
!.appveyor.yml
__pycache__
__pycache__

View File

@ -1,19 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDDjCCAfYCCQCi9L0SyIknmTANBgkqhkiG9w0BAQsFADBJMQswCQYDVQQGEwJQ
TDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIU3luY3BsYXkxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xOTAyMDMxOTA0MTFaFw0yMTExMjMxOTA0MTFaMEkx
CzAJBgNVBAYTAlBMMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhTeW5j
cGxheTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAxdnxzQ2ddPWLBHzHRlc2uGCML6MtPdTW5mOzQbj+jxHqhcJszIo4
5/ZoqCX11tgQ69cJphTmg0Pjd89xTiqQBOf/qD3kSycds6j26H4oiIsuvOCaa5LN
lE5jAGZQWWRrnAqXJgbnQZgW+2a8bhJGCospRRIK+h48FDazOwEoNHjmPC7DHWrt
HlU/BbuzGPLhekKzR7LTD8/32+4g1e2LMMEv22LYrN2cRpZqb8wXYgjsMRc7aqAA
NS7x0tspBhBfCigDLd4i+SuKPGkyI118uss7eKx7MDgmQp1vUiTOkKphgT1S/a7m
4EJ3xO+75WjIQ4bJPmLbdLWMKOXi2t7PVQIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQCADrdRY64VpPeM8c9MCn7jXDR0B7xjwoQkiyFvISCRiWZwX8QE2atjZ6jGnuB3
LBattjmjHcCNwLEvc5dZT0ioeiAvNdEbcMitYS7d2x3QIQ2n2zpSMp3speAv7mdG
YkC/oE7bbORBksjsxLCAOPOrDYijyTwDN0oTkDcuhkdztbO5Frp/5vA/i/U29Sxv
ebbJ0JXl8LJKzJqslyRv6sVxsNFH0foX7rwbXzciO4TscHHrFDZwNBhjWYPITJ7J
BBgr8Cs9ZbKFQ7+o1bUob7B8n2tKtVxAHfTQfBe68ZlcdTHfFririLjhRDVXSAFw
8ZZzQoma7VJ/1l8jcoWhdfOe
-----END CERTIFICATE-----

View File

@ -1,46 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDDjCCAfYCCQCi9L0SyIknmTANBgkqhkiG9w0BAQsFADBJMQswCQYDVQQGEwJQ
TDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIU3luY3BsYXkxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xOTAyMDMxOTA0MTFaFw0yMTExMjMxOTA0MTFaMEkx
CzAJBgNVBAYTAlBMMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhTeW5j
cGxheTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAxdnxzQ2ddPWLBHzHRlc2uGCML6MtPdTW5mOzQbj+jxHqhcJszIo4
5/ZoqCX11tgQ69cJphTmg0Pjd89xTiqQBOf/qD3kSycds6j26H4oiIsuvOCaa5LN
lE5jAGZQWWRrnAqXJgbnQZgW+2a8bhJGCospRRIK+h48FDazOwEoNHjmPC7DHWrt
HlU/BbuzGPLhekKzR7LTD8/32+4g1e2LMMEv22LYrN2cRpZqb8wXYgjsMRc7aqAA
NS7x0tspBhBfCigDLd4i+SuKPGkyI118uss7eKx7MDgmQp1vUiTOkKphgT1S/a7m
4EJ3xO+75WjIQ4bJPmLbdLWMKOXi2t7PVQIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQCADrdRY64VpPeM8c9MCn7jXDR0B7xjwoQkiyFvISCRiWZwX8QE2atjZ6jGnuB3
LBattjmjHcCNwLEvc5dZT0ioeiAvNdEbcMitYS7d2x3QIQ2n2zpSMp3speAv7mdG
YkC/oE7bbORBksjsxLCAOPOrDYijyTwDN0oTkDcuhkdztbO5Frp/5vA/i/U29Sxv
ebbJ0JXl8LJKzJqslyRv6sVxsNFH0foX7rwbXzciO4TscHHrFDZwNBhjWYPITJ7J
BBgr8Cs9ZbKFQ7+o1bUob7B8n2tKtVxAHfTQfBe68ZlcdTHfFririLjhRDVXSAFw
8ZZzQoma7VJ/1l8jcoWhdfOe
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxdnxzQ2ddPWLBHzHRlc2uGCML6MtPdTW5mOzQbj+jxHqhcJs
zIo45/ZoqCX11tgQ69cJphTmg0Pjd89xTiqQBOf/qD3kSycds6j26H4oiIsuvOCa
a5LNlE5jAGZQWWRrnAqXJgbnQZgW+2a8bhJGCospRRIK+h48FDazOwEoNHjmPC7D
HWrtHlU/BbuzGPLhekKzR7LTD8/32+4g1e2LMMEv22LYrN2cRpZqb8wXYgjsMRc7
aqAANS7x0tspBhBfCigDLd4i+SuKPGkyI118uss7eKx7MDgmQp1vUiTOkKphgT1S
/a7m4EJ3xO+75WjIQ4bJPmLbdLWMKOXi2t7PVQIDAQABAoIBAFz8ZlE58eOzNyff
wQRFHvmenqQQ68Vgj7Nt7iSYXkM9Z1yAGQQ0fjQ+scc9OAJGQAWnZeiBcCkHMhPw
Ec9r343+v0AB/pZ3htUWNxzjlgc+arPoV4rxTt9By/O3IlIxCQYoUAtWOT+xzDNR
gIO24OY5qybEKRaOOSxC3Q+BJrUpvIMEf93w7YQQ5SqulcmSYsIK25t+ACdXAlkX
KpvszojDU+qfUH7Uz8/yvFcbZ8LeDdrv1Wcedx15VUIcrU+D9DBYK1NOFW2vuPJT
DJZOQFXMTxg6kSED0O8a4Z3VhaPEBiGdN4KOIkC1tUj8i+BM441Jg4nme8OLX/Vm
NGftpm0CgYEA93w8P6gp1wnO7R56FdRoL9nhfgoMQroqNMqHdoGlWPFZNDqtvbFW
vjhg1v98T8mBvQMsfLruUuDDykacOdDyHRAbPQ+gICUjRXDFgu+GhHcIRn3dcZli
cSRka/JsuqCuTFnIoa981IYEllAQTZ+3w+qR8d+BkoR7K55v5aRxNCsCgYEAzKiM
8u1W3d6/E6EgaiSVOuCwOB85zbQH1t1s6wQoD34u+CEKyW3/WCkZuNMlE6J8luwt
HfXilFq9ZfAdyxN/DhHIygulbIbGwtzYFI6rEmU3zL1bX27ZWStjuDUyWf3zX4T2
9vlBf9CwJWeotaKl+Or2aeGAiNP5830WIpikyn8CgYEA8AjjNqqXyiWNOZaxurKF
SsP8XQ7JzX5aqVE2Cc683INZjbrMAIwcIer0ohKyM4CyAO0vHNsBhAjUXUAXDkyG
R4HzqUmaeRMMHrG+H7zJr3jz4cr6GNA4FpzBeaFrq6dk5lC+s3NNk6NYl6GX7nHW
/oJogzvQpJcyD6Bfz0+rLHkCgYBr0uFvm1uIyTIiRWGuileVDYvKBamOlqsKqN4Z
c7cncnOMhtwIA8vjxsOmfJesII9DdGrQvhsBzky6yCbqNvtZjkUbLceZxegyAehV
7FR0/J7JX3okbWJVeGaxRlWg1ArE6Gi09d1sWaZ0Doj0KR0IZ8IrRoNRk1y8y8o9
r+4iQQKBgDyuv6nz4xV3GrW6ohVcCRg8R4yZmb65A4guxZIwMh3nbf+rHWO3RTxd
LMiCLSW3Py2xsxiMa5ICEm75Hke8+KHwRBL7SK1eqaFrdhzvTALQp0IfBu1/t7bR
5bJVa6EL55eNA0LcOZqX36rDYzpzZjaf46XNzshZ/p0X7NryEhNl
-----END RSA PRIVATE KEY-----

View File

@ -108,6 +108,8 @@ class SyncplayClient(object):
self._warnings = self._WarningManager(self._player, self.userlist, self.ui, self)
self.fileSwitch = FileSwitchManager(self)
self.playlist = SyncplayPlaylist(self)
self._serverSupportsTLS = True
if constants.LIST_RELATIVE_CONFIGS and 'loadedRelativePaths' in self._config and self._config['loadedRelativePaths']:
paths = "; ".join(self._config['loadedRelativePaths'])
@ -704,11 +706,11 @@ class SyncplayClient(object):
if '[' in host:
host = host.strip('[]')
port = int(port)
with open('server.crt') as cert_file:
with open('cert/server.crt') as cert_file:
trust_root = Certificate.loadPEM(cert_file.read())
self._wrapped = HostnameEndpoint(reactor, host, port)
self._contextFactory = optionsForClientTLS(hostname=host, trustRoot=trust_root)
self._endpoint = wrapClientTLS(self._contextFactory, self._wrapped)
self._endpoint = HostnameEndpoint(reactor, host, port)
self.protocolFactory.options = optionsForClientTLS(hostname=host, trustRoot = trust_root)
def retry(retries):
self._lastGlobalUpdate = None

View File

@ -27,6 +27,8 @@ class JSONCommandProtocol(LineReceiver):
self.handleError(message[1])
elif command == "Chat":
self.handleChat(message[1])
elif command == "TLS":
self.handleTLS(message[1])
else:
self.dropWithError(getMessage("unknown-command-server-error").format(message[1])) # TODO: log, not drop
@ -72,7 +74,11 @@ class SyncClientProtocol(JSONCommandProtocol):
def connectionMade(self):
self._client.initProtocol(self)
self.sendHello()
if self._client._serverSupportsTLS:
self.sendTLS({"startTLS": "send"})
self._client.ui.showMessage("Attempting secure connection")
else:
self.sendHello()
def connectionLost(self, reason):
self._client.destroyProtocol()
@ -296,11 +302,24 @@ class SyncClientProtocol(JSONCommandProtocol):
})
def handleError(self, error):
self.dropWithError(error["message"])
if "startTLS" in error["message"] and not self.logged:
self._client.ui.showErrorMessage("This server does not support TLS")
self._client._serverSupportsTLS = False
else:
self.dropWithError(error["message"])
def sendError(self, message):
self.sendMessage({"Error": {"message": message}})
def sendTLS(self, message):
self.sendMessage({"TLS": message})
def handleTLS(self, message):
answer = message["startTLS"] if "startTLS" in message else None
if "true" in answer and not self.logged:
self.transport.startTLS(self._client.protocolFactory.options)
self._client.ui.showMessage("Secure connection established")
self.sendHello()
class SyncServerProtocol(JSONCommandProtocol):
def __init__(self, factory):
@ -602,6 +621,15 @@ class SyncServerProtocol(JSONCommandProtocol):
def sendError(self, message):
self.sendMessage({"Error": {"message": message}})
def sendTLS(self, message):
self.sendMessage({"TLS": message})
def handleTLS(self, message):
inquiry = message["startTLS"] if "startTLS" in message else None
if "send" in inquiry and not self.isLogged():
self.sendTLS({"startTLS": "true"})
self.transport.startTLS(self._factory.options)
class PingService(object):

View File

@ -15,14 +15,14 @@ except AttributeError:
from OpenSSL import crypto
from twisted.internet import reactor, ssl
from twisted.internet.endpoints import SSL4ServerEndpoint
from twisted.internet.endpoints import TCP4ServerEndpoint, TCP6ServerEndpoint
from syncplay.server import SyncFactory, ConfigurationGetter
with open('server.pem') as f:
with open('cert/server.pem') as f:
certData = f.read()
certificate = ssl.PrivateCertificate.loadPEM(certData).options()
cert = ssl.PrivateCertificate.loadPEM(certData).options()
if __name__ == '__main__':
argsGetter = ConfigurationGetter()
@ -39,8 +39,9 @@ if __name__ == '__main__':
args.max_username_length,
args.stats_db_file
)
endpoint4 = SSL4ServerEndpoint(reactor, int(args.port), certificate, interface='0.0.0.0')
factory.options = cert
endpoint4 = TCP4ServerEndpoint(reactor, int(args.port))
endpoint4.listen(factory)
endpoint6 = SSL4ServerEndpoint(reactor, int(args.port), certificate, interface='::')
endpoint6 = TCP6ServerEndpoint(reactor, int(args.port))
endpoint6.listen(factory)
reactor.run()