Source code for evennia.server.portal.ssl
"""
This is a simple context factory for auto-creating
SSL keys and certificates.
"""
import os
import sys
try:
import OpenSSL
from twisted.internet import ssl as twisted_ssl
except ImportError as error:
errstr = """
{err}
SSL requires the PyOpenSSL library:
pip install pyopenssl
"""
raise ImportError(errstr.format(err=error))
from django.conf import settings
from evennia.utils.utils import class_from_module
_GAME_DIR = settings.GAME_DIR
# messages
NO_AUTOGEN = """
{err}
Evennia could not auto-generate the SSL private key. If this error
persists, create {keyfile} yourself using third-party tools.
"""
NO_AUTOCERT = """
{err}
Evennia's SSL context factory could not automatically, create an SSL
certificate {certfile}.
A private key {keyfile} was already created. Please create {certfile}
manually using the commands valid for your operating system, for
example (linux, using the openssl program):
{exestring}
"""
_TELNET_PROTOCOL_CLASS = class_from_module(settings.TELNET_PROTOCOL_CLASS)
[docs]class SSLProtocol(_TELNET_PROTOCOL_CLASS):
"""
Communication is the same as telnet, except data transfer
is done with encryption.
"""
[docs] def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.protocol_name = "ssl"
[docs]def verify_SSL_key_and_cert(keyfile, certfile):
"""
This function looks for RSA key and certificate in the current
directory. If files ssl.key and ssl.cert does not exist, they
are created.
"""
if not (os.path.exists(keyfile) and os.path.exists(certfile)):
# key/cert does not exist. Create.
import subprocess
from Crypto.PublicKey import RSA
from twisted.conch.ssh.keys import Key
print(" Creating SSL key and certificate ... ", end=" ")
try:
# create the RSA key and store it.
KEY_LENGTH = 2048
rsa_key = Key(RSA.generate(KEY_LENGTH))
key_string = rsa_key.toString(type="OPENSSH")
with open(keyfile, "w+b") as fil:
fil.write(key_string)
except Exception as err:
print(NO_AUTOGEN.format(err=err, keyfile=keyfile))
sys.exit(5)
# try to create the certificate
CERT_EXPIRE = 365 * 20 # twenty years validity
# default:
# openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300
exestring = "openssl req -new -x509 -key %s -out %s -days %s" % (
keyfile,
certfile,
CERT_EXPIRE,
)
try:
subprocess.call(exestring)
except OSError as err:
raise OSError(
NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring)
)
print("done.")
[docs]def getSSLContext():
"""
This is called by the portal when creating the SSL context
server-side.
Returns:
ssl_context (tuple): A key and certificate that is either
existing previously or or created on the fly.
"""
keyfile = os.path.join(_GAME_DIR, "server", "ssl.key")
certfile = os.path.join(_GAME_DIR, "server", "ssl.cert")
verify_SSL_key_and_cert(keyfile, certfile)
return twisted_ssl.DefaultOpenSSLContextFactory(keyfile, certfile)