diff --git a/src/Crypt/CryptConnection.py b/src/Crypt/CryptConnection.py index f530a017..16cea1ba 100644 --- a/src/Crypt/CryptConnection.py +++ b/src/Crypt/CryptConnection.py @@ -3,6 +3,7 @@ import logging import os import ssl import hashlib +import random from Config import config from util import SslPatch @@ -11,6 +12,7 @@ from util import helper class CryptConnectionManager: def __init__(self): + # TODO: UGLY UGLY UGLY # OpenSSL params if sys.platform.startswith("win"): self.openssl_bin = "src\\lib\\opensslVerify\\openssl.exe" @@ -19,6 +21,11 @@ class CryptConnectionManager: self.openssl_env = {"OPENSSL_CONF": "src/lib/opensslVerify/openssl.cnf"} self.crypt_supported = [] # Supported cryptos + self.cacert_pem = config.data_dir+"/cacert-rsa.pem" + self.cakey_pem = config.data_dir+"/cakey-rsa.pem" + self.cert_pem = config.data_dir+"/cert-rsa.pem" + self.cert_csr = config.data_dir+"/cert-rsa.csr" + self.key_pem = config.data_dir+"/key-rsa.pem" # Select crypt that supported by both sides # Return: Name of the crypto @@ -36,8 +43,8 @@ class CryptConnectionManager: ciphers += "!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK" if server: sock_wrapped = ssl.wrap_socket( - sock, server_side=server, keyfile='%s/key-rsa.pem' % config.data_dir, - certfile='%s/cert-rsa.pem' % config.data_dir, ciphers=ciphers) + sock, server_side=server, keyfile=self.key_pem, + certfile=self.cert_pem, ciphers=ciphers) else: sock_wrapped = ssl.wrap_socket(sock, ciphers=ciphers) if cert_pin: @@ -50,7 +57,7 @@ class CryptConnectionManager: def removeCerts(self): if config.keep_ssl_cert: return False - for file_name in ["cert-rsa.pem", "key-rsa.pem"]: + for file_name in ["cert-rsa.pem", "key-rsa.pem", "cacert-rsa.pem", "cakey-rsa.pem", "cert-rsa.csr"]: file_path = "%s/%s" % (config.data_dir, file_name) if os.path.isfile(file_path): os.unlink(file_path) @@ -66,15 +73,60 @@ class CryptConnectionManager: # Try to create RSA server cert + sign for connection encryption # Return: True on success def createSslRsaCert(self): - if os.path.isfile("%s/cert-rsa.pem" % config.data_dir) and os.path.isfile("%s/key-rsa.pem" % config.data_dir): + casubjects = [ + "/C=US/O=Amazon/OU=Server CA 1B/CN=Amazon", + "/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3", + "/C=US/O=DigiCert Inc/OU=www.digicert.com/CN = DigiCert SHA2 High Assurance Server CA", + "/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN = COMODO RSA Domain Validation Secure Server CA" + ] + fakedomains = [ + "yahoo.com", + "amazon.com", + "live.com", + "microsoft.com", + "mail.ru", + "csdn.net", + "bing.com", + "amazon.co.jp", + "office.com", + "imdb.com", + "msn.com", + "samsung.com", + "huawei.com", + "ztedevices.com", + "godaddy.com", + "w3.org", + "gravatar.com", + "creativecommons.org", + "hatena.ne.jp", + "adobe.com", + "opera.com", + "apache.org", + "rambler.ru", + "one.com", + "nationalgeographic.com", + "networksolutions.com", + "php.net", + "python.org", + "phoca.cz", + "debian.org", + "ubuntu.com", + "nazwa.pl", + "symantec.com" + ] + self.openssl_env['CN'] = random.choice(fakedomains) + + if os.path.isfile(self.cert_pem) and os.path.isfile(self.key_pem): return True # Files already exits import subprocess - cmd = "%s req -x509 -newkey rsa:2048 -sha256 -batch -keyout %s -out %s -nodes -config %s" % helper.shellquote( + # Generate CAcert and CAkey + cmd = "%s req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj %s -keyout %s -out %s -batch -config %s" % helper.shellquote( self.openssl_bin, - config.data_dir+"/key-rsa.pem", - config.data_dir+"/cert-rsa.pem", - self.openssl_env["OPENSSL_CONF"] + random.choice(casubjects), + self.cakey_pem, + self.cacert_pem, + self.openssl_env["OPENSSL_CONF"], ) proc = subprocess.Popen( cmd.encode(sys.getfilesystemencoding()), @@ -82,9 +134,46 @@ class CryptConnectionManager: ) back = proc.stdout.read().strip() proc.wait() - logging.debug("Generating RSA cert and key PEM files...%s" % back) + logging.debug("Generating RSA CAcert and CAkey PEM files...%s" % back) - if os.path.isfile("%s/cert-rsa.pem" % config.data_dir) and os.path.isfile("%s/key-rsa.pem" % config.data_dir): + if not (os.path.isfile(self.cacert_pem) and os.path.isfile(self.cakey_pem)): + logging.error("RSA ECC SSL CAcert generation failed, CAcert or CAkey files not exist.") + return False + + # Generate certificate key and signing request + cmd = "%s req -new -newkey rsa:2048 -keyout %s -out %s -subj %s -sha256 -nodes -batch -config %s" % helper.shellquote( + self.openssl_bin, + self.key_pem, + self.cert_csr, + "/CN="+self.openssl_env['CN'], + self.openssl_env["OPENSSL_CONF"], + ) + proc = subprocess.Popen( + cmd.encode(sys.getfilesystemencoding()), + shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=self.openssl_env + ) + back = proc.stdout.read().strip() + proc.wait() + logging.debug("Generating certificate key and signing request...%s" % back) + + # Sign request and generate certificate + cmd = "%s x509 -req -in %s -CA %s -CAkey %s -CAcreateserial -out %s -days 730 -sha256 -extensions x509_ext -extfile %s" % helper.shellquote( + self.openssl_bin, + self.cert_csr, + self.cacert_pem, + self.cakey_pem, + self.cert_pem, + self.openssl_env["OPENSSL_CONF"], + ) + proc = subprocess.Popen( + cmd.encode(sys.getfilesystemencoding()), + shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=self.openssl_env + ) + back = proc.stdout.read().strip() + proc.wait() + logging.debug("Generating RSA cert...%s" % back) + + if os.path.isfile(self.cert_pem) and os.path.isfile(self.key_pem): return True else: logging.error("RSA ECC SSL cert generation failed, cert or key files not exist.") diff --git a/src/lib/opensslVerify/openssl.cnf b/src/lib/opensslVerify/openssl.cnf index a2c48ba1..61178008 100644 --- a/src/lib/opensslVerify/openssl.cnf +++ b/src/lib/opensslVerify/openssl.cnf @@ -1,5 +1,5 @@ [ req ] -prompt = no +prompt = yes default_bits = 2048 default_keyfile = server-key.pem distinguished_name = subject @@ -32,8 +32,8 @@ authorityKeyIdentifier = keyid,issuer basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth, serverAuth subjectAltName = @alternate_names -nsComment = "OpenSSL Generated Certificate" # RFC 5280, Section 4.2.1.12 makes EKU optional # CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused @@ -46,8 +46,8 @@ subjectKeyIdentifier = hash basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth, serverAuth subjectAltName = @alternate_names -nsComment = "OpenSSL Generated Certificate" # RFC 5280, Section 4.2.1.12 makes EKU optional # CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused @@ -55,16 +55,5 @@ nsComment = "OpenSSL Generated Certificate" [ alternate_names ] -DNS.1 = example.com -DNS.2 = www.example.com -DNS.3 = mail.example.com -DNS.4 = ftp.example.com - -# Add these if you need them. But usually you don't want them or -# need them in production. You may need them for development. -# DNS.5 = localhost -# DNS.6 = localhost.localdomain -# DNS.7 = 127.0.0.1 - -# IPv6 localhost -# DNS.8 = ::1 \ No newline at end of file +DNS.1 = $ENV::CN +DNS.2 = www.$ENV::CN