mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-21 09:34:08 +03:00
Merge remote-tracking branch 'origin/v3.6'
This commit is contained in:
commit
d55c0e9593
@ -51,6 +51,19 @@ from .log import logger
|
||||
# Server before this version uses "unsigned" scripts
|
||||
OLD_METHOD_VERSION = '2.4.0'
|
||||
|
||||
SECURE_CIPHERS = (
|
||||
'TLS_AES_256_GCM_SHA384'
|
||||
':TLS_CHACHA20_POLY1305_SHA256'
|
||||
':TLS_AES_128_GCM_SHA256'
|
||||
':ECDHE-RSA-AES256-GCM-SHA384'
|
||||
':ECDHE-RSA-AES128-GCM-SHA256'
|
||||
':ECDHE-RSA-CHACHA20-POLY1305'
|
||||
':ECDHE-ECDSA-AES128-GCM-SHA256'
|
||||
':ECDHE-ECDSA-AES256-GCM-SHA384'
|
||||
':ECDHE-ECDSA-AES128-SHA256'
|
||||
':ECDHE-ECDSA-CHACHA20-POLY1305'
|
||||
)
|
||||
|
||||
# Callback for error on cert
|
||||
# parameters are hostname, serial
|
||||
# If returns True, ignores error
|
||||
@ -72,7 +85,6 @@ class InvalidVersion(UDSException):
|
||||
super().__init__(downloadUrl)
|
||||
self.downloadUrl = downloadUrl
|
||||
|
||||
|
||||
class RestApi:
|
||||
|
||||
_restApiUrl: str # base Rest API URL
|
||||
@ -186,6 +198,7 @@ class RestApi:
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
# Disable SSLv2, SSLv3, TLSv1, TLSv1.1
|
||||
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
ctx.set_ciphers(SECURE_CIPHERS)
|
||||
|
||||
# If we have the certificates file, we use it
|
||||
if tools.getCaCertsFile() is not None:
|
||||
|
@ -163,6 +163,23 @@ SECRET_KEY = 's5ky!7b5f#s35!e38xv%e-+iey6yi-#630x)kk3kk5_j8rie2*'
|
||||
# This is a very long string, an RSA KEY (this can be changed, but if u loose it, all encription will be lost)
|
||||
RSA_KEY = '-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQC0qe1GlriQbHFYdKYRPBFDSS8Ne/TEKI2mtPKJf36XZTy6rIyH\nvUpT1gMScVjHjOISLNJQqktyv0G+ZGzLDmfkCUBev6JBlFwNeX3Dv/97Q0BsEzJX\noYHiDANUkuB30ukmGvG0sg1v4ccl+xs2Su6pFSc5bGINBcQ5tO0ZI6Q1nQIDAQAB\nAoGBAKA7Octqb+T/mQOX6ZXNjY38wXOXJb44LXHWeGnEnvUNf/Aci0L0epCidfUM\nfG33oKX4BMwwTVxHDrsa/HaXn0FZtbQeBVywZqMqWpkfL/Ho8XJ8Rsq8OfElrwek\nOCPXgxMzQYxoNHw8V97k5qhfupQ+h878BseN367xSyQ8plahAkEAuPgAi6aobwZ5\nFZhx/+6rmQ8sM8FOuzzm6bclrvfuRAUFa9+kMM2K48NAneAtLPphofqI8wDPCYgQ\nTl7O96GXVQJBAPoKtWIMuBHJXKCdUNOISmeEvEzJMPKduvyqnUYv17tM0JTV0uzO\nuDpJoNIwVPq5c3LJaORKeCZnt3dBrdH1FSkCQQC3DK+1hIvhvB0uUvxWlIL7aTmM\nSny47Y9zsc04N6JzbCiuVdeueGs/9eXHl6f9gBgI7eCD48QAocfJVygphqA1AkEA\nrvzZjcIK+9+pJHqUO0XxlFrPkQloaRK77uHUaW9IEjui6dZu4+2T/q7SjubmQgWR\nZy7Pap03UuFZA2wCoqJbaQJAUG0FVrnyUORUnMQvdDjAWps2sXoPvA8sbQY1W8dh\nR2k4TCFl2wD7LutvsdgdkiH0gWdh5tc1c4dRmSX1eQ27nA==\n-----END RSA PRIVATE KEY-----'
|
||||
|
||||
# Trusted cyphers
|
||||
SECURE_CIPHERS = (
|
||||
'TLS_AES_256_GCM_SHA384'
|
||||
':TLS_CHACHA20_POLY1305_SHA256'
|
||||
':TLS_AES_128_GCM_SHA256'
|
||||
':ECDHE-RSA-AES256-GCM-SHA384'
|
||||
':ECDHE-RSA-AES128-GCM-SHA256'
|
||||
':ECDHE-RSA-CHACHA20-POLY1305'
|
||||
':ECDHE-ECDSA-AES128-GCM-SHA256'
|
||||
':ECDHE-ECDSA-AES256-GCM-SHA384'
|
||||
':ECDHE-ECDSA-AES128-SHA256'
|
||||
':ECDHE-ECDSA-CHACHA20-POLY1305'
|
||||
)
|
||||
# Min TLS version
|
||||
SECURE_MIN_TLS_VERSION = '1.2'
|
||||
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
|
@ -90,7 +90,7 @@ def _requestActor(
|
||||
r = proxy.doProxyRequest(url=url, data=data, timeout=TIMEOUT)
|
||||
else:
|
||||
verify: typing.Union[bool, str]
|
||||
cert = userService.getProperty('cert')
|
||||
cert = userService.getProperty('cert') or ''
|
||||
# cert = '' # Uncomment to test without cert
|
||||
if cert:
|
||||
# Generate temp file, and delete it after
|
||||
@ -99,7 +99,7 @@ def _requestActor(
|
||||
f.write(cert.encode()) # Save cert
|
||||
else:
|
||||
verify = False
|
||||
session = secureRequestsSession(verify=bool(cert))
|
||||
session = secureRequestsSession(verify=cert)
|
||||
if data is None:
|
||||
r = session.get(url, verify=verify, timeout=TIMEOUT)
|
||||
else:
|
||||
|
@ -3,8 +3,10 @@ import random
|
||||
from datetime import datetime, timedelta
|
||||
import ipaddress
|
||||
import typing
|
||||
import logging
|
||||
import ssl
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import NameOID
|
||||
@ -16,9 +18,13 @@ import certifi
|
||||
import requests
|
||||
import requests.adapters
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
KEY_SIZE = 4096
|
||||
SECRET_SIZE = 32
|
||||
|
||||
|
||||
|
||||
try:
|
||||
# Ensure that we do not get warnings about self signed certificates and so
|
||||
import requests.packages.urllib3 # type: ignore
|
||||
@ -85,13 +91,21 @@ def createClientSslContext(verify: bool = True) -> ssl.SSLContext:
|
||||
sslContext = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=certifi.where())
|
||||
if not verify:
|
||||
sslContext.check_hostname = False
|
||||
sslContext.verify_mode = ssl.CERT_NONE
|
||||
sslContext.verify_mode = ssl.VerifyMode.CERT_NONE
|
||||
|
||||
# Disable TLS1.0 and TLS1.1, SSLv2 and SSLv3 are disabled by default
|
||||
# Next line is deprecated in Python 3.7
|
||||
# sslContext.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
||||
sslContext.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
if hasattr(settings, 'SECURE_MIN_TLS_VERSION') and settings.SECURE_MIN_TLS_VERSION:
|
||||
# format is "1.0, 1.1, 1.2 or 1.3", convert to ssl.TLSVersion.TLSv1_0, ssl.TLSVersion.TLSv1_1, ssl.TLSVersion.TLSv1_2 or ssl.TLSVersion.TLSv1_3
|
||||
sslContext.minimum_version = getattr(ssl.TLSVersion, 'TLSv' + settings.SECURE_MIN_TLS_VERSION.replace('.', '_'))
|
||||
else:
|
||||
sslContext.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
|
||||
sslContext.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
|
||||
if hasattr(settings, 'SECURE_CIPHERS') and settings.SECURE_CIPHERS:
|
||||
sslContext.set_ciphers(settings.SECURE_CIPHERS)
|
||||
|
||||
return sslContext
|
||||
|
||||
|
||||
@ -126,7 +140,7 @@ def checkCertificateMatchPrivateKey(*, cert: str, key: str) -> bool:
|
||||
# Even if the key or certificate is not valid, we only want a True if they match, False otherwise
|
||||
return False
|
||||
|
||||
def secureRequestsSession(*, verify: bool = True) -> 'requests.Session':
|
||||
def secureRequestsSession(*, verify: typing.Union[str, bool] = True) -> 'requests.Session':
|
||||
'''
|
||||
Generates a requests.Session object with a custom adapter that uses a custom SSLContext.
|
||||
This is intended to be used for requests that need to be secure, but not necessarily verified.
|
||||
@ -140,16 +154,36 @@ def secureRequestsSession(*, verify: bool = True) -> 'requests.Session':
|
||||
'''
|
||||
class UDSHTTPAdapter(requests.adapters.HTTPAdapter):
|
||||
def init_poolmanager(self, *args, **kwargs) -> None:
|
||||
sslContext = createClientSslContext(verify=verify)
|
||||
|
||||
# See urllib3.poolmanager.SSL_KEYWORDS for all available keys.
|
||||
kwargs["ssl_context"] = sslContext
|
||||
kwargs["ssl_context"] = createClientSslContext(verify=verify is True)
|
||||
|
||||
|
||||
# See urllib3.poolmanager.SSL_KEYWORDS for all available keys.
|
||||
return super().init_poolmanager(*args, **kwargs)
|
||||
|
||||
def cert_verify(self, conn, url, _, cert):
|
||||
# Overridden to disable cert verification if verify is False
|
||||
return super().cert_verify(conn, url, verify, cert)
|
||||
def cert_verify(self, conn, url, lverify, cert) -> None:
|
||||
"""Verify a SSL certificate. This method should not be called from user
|
||||
code, and is only exposed for use when subclassing the
|
||||
:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
|
||||
|
||||
:param conn: The urllib3 connection object associated with the cert.
|
||||
:param url: The requested URL.
|
||||
:param verify: Either a boolean, in which case it controls whether we verify
|
||||
the server's TLS certificate, or a string, in which case it must be a path
|
||||
to a CA bundle to use
|
||||
:param cert: The SSL certificate to verify.
|
||||
"""
|
||||
|
||||
# If lverify is an string, use it even if verify is False
|
||||
# if not, use verify value
|
||||
if not isinstance(lverify, str):
|
||||
lverify = verify
|
||||
|
||||
# logger.info('Connection info: %s', conn)
|
||||
# for k, v in conn.__dict__.items():
|
||||
# logger.info('Connection info: %s = %s', k, v)
|
||||
|
||||
|
||||
super().cert_verify(conn, url, lverify, cert)
|
||||
|
||||
session = requests.Session()
|
||||
session.mount("https://", UDSHTTPAdapter())
|
||||
|
@ -55,6 +55,7 @@ class ConfigurationType(typing.NamedTuple):
|
||||
|
||||
workers: int
|
||||
|
||||
ssl_min_tls_version: str # Valid values are 1.2, 1.3 (1.0 and 1.1 are not supported)
|
||||
ssl_certificate: str
|
||||
ssl_certificate_key: str
|
||||
ssl_password: str
|
||||
@ -131,6 +132,7 @@ def read(
|
||||
listen_port=int(uds.get('port', '443')),
|
||||
ipv6=uds.get('ipv6', 'false').lower() == 'true',
|
||||
workers=int(uds.get('workers', '0')) or multiprocessing.cpu_count(),
|
||||
ssl_min_tls_version=uds.get('ssl_min_tls_version', '1.2'),
|
||||
ssl_certificate=uds['ssl_certificate'],
|
||||
ssl_certificate_key=uds.get('ssl_certificate_key', ''),
|
||||
ssl_password=uds.get('ssl_password', ''),
|
||||
|
@ -150,6 +150,11 @@ async def tunnel_proc_async(
|
||||
|
||||
context.load_cert_chain(**args)
|
||||
|
||||
# Set min version from string (1.2 or 1.3) as ssl.TLSVersion.TLSv1_2 or ssl.TLSVersion.TLSv1_3
|
||||
if cfg.ssl_min_tls_version in ('1.2', '1.3'):
|
||||
context.minimum_version = getattr(ssl.TLSVersion, f'TLSv1_{cfg.ssl_min_tls_version.split(".")[1]}')
|
||||
# Any other value will be ignored
|
||||
|
||||
if cfg.ssl_ciphers:
|
||||
context.set_ciphers(cfg.ssl_ciphers)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user