Randomize SSL subject (merged ValdikSS's commit)

This commit is contained in:
shortcutme 2019-03-27 03:08:37 +01:00
parent cf354d59fb
commit 3d8d3a9237
No known key found for this signature in database
GPG Key ID: 5B63BAE6CB9613AE
2 changed files with 86 additions and 32 deletions

View File

@ -3,6 +3,7 @@ import logging
import os import os
import ssl import ssl
import hashlib import hashlib
import random
from Config import config from Config import config
from util import helper from util import helper
@ -12,13 +13,19 @@ class CryptConnectionManager:
def __init__(self): def __init__(self):
# OpenSSL params # OpenSSL params
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
self.openssl_bin = "src\\lib\\opensslVerify\\openssl.exe" self.openssl_bin = "dist\\openssl\\openssl.exe"
else: else:
self.openssl_bin = "openssl" self.openssl_bin = "openssl"
self.openssl_env = {"OPENSSL_CONF": "src/lib/openssl/openssl.cnf"} self.openssl_env = {"OPENSSL_CONF": "src/lib/openssl/openssl.cnf"}
self.crypt_supported = [] # Supported cryptos 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 # Select crypt that supported by both sides
# Return: Name of the crypto # Return: Name of the crypto
def selectCrypt(self, client_supported): def selectCrypt(self, client_supported):
@ -35,8 +42,9 @@ class CryptConnectionManager:
ciphers += "!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK" ciphers += "!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK"
if server: if server:
sock_wrapped = ssl.wrap_socket( sock_wrapped = ssl.wrap_socket(
sock, server_side=server, keyfile='%s/key-rsa.pem' % config.data_dir, sock, server_side=server, keyfile=self.key_pem,
certfile='%s/cert-rsa.pem' % config.data_dir, ciphers=ciphers) certfile=self.cert_pem, ciphers=ciphers
)
else: else:
sock_wrapped = ssl.wrap_socket(sock, ciphers=ciphers) sock_wrapped = ssl.wrap_socket(sock, ciphers=ciphers)
if cert_pin: if cert_pin:
@ -49,7 +57,7 @@ class CryptConnectionManager:
def removeCerts(self): def removeCerts(self):
if config.keep_ssl_cert: if config.keep_ssl_cert:
return False 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", "cacert-rsa.srl", "cert-rsa.csr"]:
file_path = "%s/%s" % (config.data_dir, file_name) file_path = "%s/%s" % (config.data_dir, file_name)
if os.path.isfile(file_path): if os.path.isfile(file_path):
os.unlink(file_path) os.unlink(file_path)
@ -65,28 +73,86 @@ class CryptConnectionManager:
# Try to create RSA server cert + sign for connection encryption # Try to create RSA server cert + sign for connection encryption
# Return: True on success # Return: True on success
def createSslRsaCert(self): 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 return True # Files already exits
import subprocess 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_params = helper.shellquote(
self.openssl_bin, self.openssl_bin,
config.data_dir + "/key-rsa.pem", self.openssl_env["OPENSSL_CONF"],
config.data_dir + "/cert-rsa.pem", random.choice(casubjects),
self.openssl_env["OPENSSL_CONF"] self.cakey_pem,
self.cacert_pem
) )
cmd = "%s req -new -newkey rsa:2048 -days 3650 -nodes -x509 -config %s -subj %s -keyout %s -out %s -batch" % cmd_params
proc = subprocess.Popen( proc = subprocess.Popen(
cmd, shell=True, stderr=subprocess.STDOUT, cmd, shell=True, stderr=subprocess.STDOUT,
stdout=subprocess.PIPE, env=self.openssl_env stdout=subprocess.PIPE, env=self.openssl_env
) )
back = proc.stdout.read().strip() back = proc.stdout.read().strip()
proc.wait() proc.wait()
logging.debug("Generating RSA cert and key PEM files...%s" % back) logging.debug("Generating RSA CAcert and CAkey PEM files... %s: %s" % (cmd, back.decode()))
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)):
return True logging.error("RSA ECC SSL CAcert generation failed, CAcert or CAkey files not exist.")
else:
logging.error("RSA SSL cert generation failed, cert or key files not exist.")
return False return False
# Generate certificate key and signing request
cmd_params = helper.shellquote(
self.openssl_bin,
self.key_pem,
self.cert_csr,
"/CN=" + self.openssl_env['CN'],
self.openssl_env["OPENSSL_CONF"],
)
cmd = "%s req -new -newkey rsa:2048 -keyout %s -out %s -subj %s -sha256 -nodes -batch -config %s" % cmd_params
proc = subprocess.Popen(
cmd, 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.decode())
# Sign request and generate certificate
cmd_params = helper.shellquote(
self.openssl_bin,
self.cert_csr,
self.cacert_pem,
self.cakey_pem,
self.cert_pem,
self.openssl_env["OPENSSL_CONF"]
)
cmd = "%s x509 -req -in %s -CA %s -CAkey %s -CAcreateserial -out %s -days 730 -sha256 -extensions x509_ext -extfile %s" % cmd_params
proc = subprocess.Popen(
cmd, 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.decode())
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.")
manager = CryptConnectionManager() manager = CryptConnectionManager()

View File

@ -1,6 +1,5 @@
[ req ] [ req ]
prompt = no default_bits = 2048
default_bits = 1024
default_keyfile = server-key.pem default_keyfile = server-key.pem
distinguished_name = subject distinguished_name = subject
req_extensions = req_ext req_extensions = req_ext
@ -13,7 +12,7 @@ string_mask = utf8only
countryName = US countryName = US
stateOrProvinceName = NY stateOrProvinceName = NY
localityName = New York localityName = New York
organizationName = Example Company, LLC organizationName = Example, LLC
# Use a friendly name here because its presented to the user. The server's DNS # Use a friendly name here because its presented to the user. The server's DNS
# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated # names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
@ -32,8 +31,8 @@ authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectAltName = @alternate_names subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
# RFC 5280, Section 4.2.1.12 makes EKU optional # RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused # CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
@ -46,8 +45,8 @@ subjectKeyIdentifier = hash
basicConstraints = CA:FALSE basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectAltName = @alternate_names subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
# RFC 5280, Section 4.2.1.12 makes EKU optional # RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused # CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
@ -55,16 +54,5 @@ nsComment = "OpenSSL Generated Certificate"
[ alternate_names ] [ alternate_names ]
DNS.1 = example.company.com DNS.1 = $ENV::CN
DNS.2 = www.example.company.com DNS.2 = www.$ENV::CN
DNS.3 = mail.example.company.com
DNS.4 = ftp.example.company.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