[Servers] Moved check_ssl_keys and generate_ssl_keys to crypto_utils.py

With this change, we drop a core dependency from the UI. This will help group together
all related functionality in one place, i.e. all security related functions.

Also updated testssl.sh version to 3.0.6 (SECURITY_TEST)

Closes: deluge-torrent/deluge#288
This commit is contained in:
DjLegolas 2020-05-01 11:37:11 +03:00 committed by Calum Lind
parent 6a10e57f7e
commit 88ffd1b843
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
5 changed files with 82 additions and 65 deletions

View File

@ -41,12 +41,25 @@ jobs:
key-server: keyserver.ubuntu.com
install: python3-libtorrent-dbg
- name: Sets env var for security
if: (github.event_name == 'pull_request' && contains(github.event.pull_request.body, 'security_test')) || (github.event_name == 'push' && contains(github.event.head_commit.message, 'security_test'))
run: echo "SECURITY_TESTS=True" >> $GITHUB_ENV
- name: Install dependencies
run: |
pip install --upgrade pip wheel
pip install -r requirements.txt -r requirements-tests.txt
pip install -e .
- name: Install security dependencies
if: contains(env.SECURITY_TESTS, 'True')
run: |
wget -O- $TESTSSL_URL$TESTSSL_VER | tar xz
mv -t deluge/tests/data testssl.sh-$TESTSSL_VER/testssl.sh testssl.sh-$TESTSSL_VER/etc/;
env:
TESTSSL_VER: 3.0.6
TESTSSL_URL: https://codeload.github.com/drwetter/testssl.sh/tar.gz/refs/tags/v
- name: Setup core dump directory
run: |
sudo mkdir /cores/ && sudo chmod 777 /cores/
@ -57,7 +70,7 @@ jobs:
ulimit -c unlimited # Enable core dumps to be captured
cp /usr/lib/python3/dist-packages/libtorrent*.so $GITHUB_WORKSPACE/deluge
python -c 'from deluge._libtorrent import lt; print(lt.__version__)';
catchsegv python -X dev -m pytest -v -m "not (todo or gtkui or security)" deluge
catchsegv python -X dev -m pytest -v -m "not (todo or gtkui)" deluge
- uses: actions/upload-artifact@v2
# capture all crashes as build artifacts

View File

@ -12,13 +12,11 @@ from __future__ import unicode_literals
import logging
import os
import stat
import sys
import traceback
from collections import namedtuple
from types import FunctionType
from OpenSSL import crypto
from twisted.internet import defer, reactor
from twisted.internet.protocol import Factory, connectionDone
@ -29,7 +27,7 @@ from deluge.core.authmanager import (
AUTH_LEVEL_DEFAULT,
AUTH_LEVEL_NONE,
)
from deluge.crypto_utils import get_context_factory
from deluge.crypto_utils import check_ssl_keys, get_context_factory
from deluge.error import (
DelugeError,
IncompatibleClient,
@ -588,59 +586,3 @@ class RPCServer(component.Component):
def stop(self):
self.factory.state = 'stopping'
def check_ssl_keys():
"""
Check for SSL cert/key and create them if necessary
"""
ssl_dir = deluge.configmanager.get_config_dir('ssl')
if not os.path.exists(ssl_dir):
# The ssl folder doesn't exist so we need to create it
os.makedirs(ssl_dir)
generate_ssl_keys()
else:
for f in ('daemon.pkey', 'daemon.cert'):
if not os.path.exists(os.path.join(ssl_dir, f)):
generate_ssl_keys()
break
def generate_ssl_keys():
"""
This method generates a new SSL key/cert.
"""
from deluge.common import PY2
digest = 'sha256' if not PY2 else b'sha256'
# Generate key pair
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
# Generate cert request
req = crypto.X509Req()
subj = req.get_subject()
setattr(subj, 'CN', 'Deluge Daemon')
req.set_pubkey(pkey)
req.sign(pkey, digest)
# Generate certificate
cert = crypto.X509()
cert.set_serial_number(0)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 3) # Three Years
cert.set_issuer(req.get_subject())
cert.set_subject(req.get_subject())
cert.set_pubkey(req.get_pubkey())
cert.sign(pkey, digest)
# Write out files
ssl_dir = deluge.configmanager.get_config_dir('ssl')
with open(os.path.join(ssl_dir, 'daemon.pkey'), 'wb') as _file:
_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
with open(os.path.join(ssl_dir, 'daemon.cert'), 'wb') as _file:
_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
# Make the files only readable by this user
for f in ('daemon.pkey', 'daemon.cert'):
os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE)

View File

@ -9,6 +9,10 @@
from __future__ import division, print_function, unicode_literals
import os
import stat
from OpenSSL import crypto
from OpenSSL.crypto import FILETYPE_PEM
from twisted.internet.ssl import (
AcceptableCiphers,
@ -18,6 +22,8 @@ from twisted.internet.ssl import (
TLSVersion,
)
import deluge.configmanager
# A TLS ciphers list.
# Sources for more information on TLS ciphers:
# - https://wiki.mozilla.org/Security/Server_Side_TLS
@ -77,3 +83,59 @@ def get_context_factory(cert_path, pkey_path):
ctx.set_options(SSL_OP_NO_RENEGOTIATION)
return cert_options
def check_ssl_keys():
"""
Check for SSL cert/key and create them if necessary
"""
ssl_dir = deluge.configmanager.get_config_dir('ssl')
if not os.path.exists(ssl_dir):
# The ssl folder doesn't exist so we need to create it
os.makedirs(ssl_dir)
generate_ssl_keys()
else:
for f in ('daemon.pkey', 'daemon.cert'):
if not os.path.exists(os.path.join(ssl_dir, f)):
generate_ssl_keys()
break
def generate_ssl_keys():
"""
This method generates a new SSL key/cert.
"""
from deluge.common import PY2
digest = 'sha256' if not PY2 else b'sha256'
# Generate key pair
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
# Generate cert request
req = crypto.X509Req()
subj = req.get_subject()
setattr(subj, 'CN', 'Deluge Daemon')
req.set_pubkey(pkey)
req.sign(pkey, digest)
# Generate certificate
cert = crypto.X509()
cert.set_serial_number(0)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 3) # Three Years
cert.set_issuer(req.get_subject())
cert.set_subject(req.get_subject())
cert.set_pubkey(req.get_pubkey())
cert.sign(pkey, digest)
# Write out files
ssl_dir = deluge.configmanager.get_config_dir('ssl')
with open(os.path.join(ssl_dir, 'daemon.pkey'), 'wb') as _file:
_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
with open(os.path.join(ssl_dir, 'daemon.cert'), 'wb') as _file:
_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
# Make the files only readable by this user
for f in ('daemon.pkey', 'daemon.cert'):
os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE)

View File

@ -45,6 +45,7 @@ class SecurityBaseTestCase(object):
get_test_data_file('testssl.sh'),
'--quiet',
'--nodns',
'none',
'--color',
'0',
test,
@ -55,11 +56,11 @@ class SecurityBaseTestCase(object):
def on_result(results):
if test == '-e':
results = results[0].split('\n')[7:-6]
results = results[0].split(b'\n')[7:-6]
self.assertTrue(len(results) > 3)
else:
self.assertIn('OK', results[0])
self.assertNotIn('NOT ok', results[0])
self.assertIn(b'OK', results[0])
self.assertNotIn(b'NOT ok', results[0])
d.addCallback(on_result)
return d

View File

@ -23,8 +23,7 @@ from twisted.web.resource import EncodingResourceWrapper
from deluge import common, component, configmanager
from deluge.common import is_ipv6
from deluge.core.rpcserver import check_ssl_keys
from deluge.crypto_utils import get_context_factory
from deluge.crypto_utils import check_ssl_keys, get_context_factory
from deluge.i18n import set_language, setup_translation
from deluge.ui.tracker_icons import TrackerIcons
from deluge.ui.web.auth import Auth