From d7745e451adf7abb1db9e69e346e65bf65f2b3ac Mon Sep 17 00:00:00 2001 From: Jerome Sagnole Date: Mon, 13 Nov 2017 21:18:48 +0100 Subject: [PATCH] Manager can be use TLS1.2 --- code/khaganat/tools/client.py | 80 +++- code/khaganat/tools/create_certificate.py | 422 ++++++++++++++++++ code/khaganat/tools/khaganat.cfg | 9 +- code/khaganat/tools/{manage.py => manager.py} | 69 ++- dist/docker/server/debian/common/khaganat.cfg | 7 +- 5 files changed, 545 insertions(+), 42 deletions(-) create mode 100755 code/khaganat/tools/create_certificate.py rename code/khaganat/tools/{manage.py => manager.py} (93%) diff --git a/code/khaganat/tools/client.py b/code/khaganat/tools/client.py index f33d2a062..53439c639 100755 --- a/code/khaganat/tools/client.py +++ b/code/khaganat/tools/client.py @@ -54,6 +54,8 @@ import logging import logging.config import http.client import json +import socket +import ssl def cmp_to_key(): 'compare key (check if int or other)' @@ -92,14 +94,52 @@ def cmp_to_key(): return self.obj != other.obj return K +class HTTPSConnectionCertificate(http.client.HTTPConnection): + """ Class HTTP connection with check certificate (if certicate is defined) """ + def __init__(self, key_file, cert_file, ca_cert, host='localhost', port=8000, timeout=10): + """ + Constructor + """ + logging.debug("constructor") + http.client.HTTPConnection.__init__(self, host, port, timeout) + self.key_file = key_file + self.cert_file = cert_file + self.ca_cert = ca_cert + self.host = host + self.port = port + + def connect(self): + """ + connect in https (and check certificate if defined) + """ + logging.debug("connect launched") + sock = socket.create_connection((self.host, self.port), self.timeout) + # If there's no CA File, don't force Server Certificate Check + if self.ca_cert: + logging.debug("key_file: " + self.key_file) + logging.debug("cert_file: " + self.cert_file) + logging.debug("ca_cert: " + self.ca_cert) + self.sock = ssl.wrap_socket(sock, + self.key_file, + self.cert_file, + ca_certs=self.ca_cert, + cert_reqs=ssl.CERT_REQUIRED, + ssl_version=ssl.PROTOCOL_TLSv1_2 #PROTOCOL_SSLv23 #, ciphers="ADH-AES256-SHA" + ) + else: + self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_NONE) + + def send_json(jsonin={}, command='GET', path='/', host='localhost', port=8000, raw_data=False, remove_color=False, - key_file=None, cert_file=None): - "send command with https & json format" - conn = http.client.HTTPSConnection(host=host, port=port, key_file=key_file, cert_file=cert_file ) + key_file=None, cert_file=None, ca_cert=None, timeout=10): + """ + send command with https & json format + """ + + conn = HTTPSConnectionCertificate(host=host, port=port, key_file=key_file, cert_file=cert_file, ca_cert=ca_cert, timeout=timeout) conn.putrequest(command, path) out=json.dumps(jsonin) conn.putheader('Content-type', 'application/json') - #length = int(self.headers.getheader('content-length')) conn.putheader('Content-length', len(out)) conn.endheaders() conn.send(bytes(out, "utf-8")) @@ -126,8 +166,8 @@ def send_json(jsonin={}, command='GET', path='/', host='localhost', port=8000, r print("%s: %s %s" % (key, msgjson[key], endText)) -def main(server, command, program, action, firstline, fileLog, logLevel, show_log_console, port=8000, - raw_data=False, remove_color=False, key_file=None, cert_file=None): +def main(host, command, program, action, firstline, fileLog, logLevel, show_log_console, port=8000, + raw_data=False, remove_color=False, key_file=None, cert_file=None, ca_cert=None): # Manage log logging.getLogger('logging') numeric_level = getattr(logging, logLevel.upper(), None) @@ -142,19 +182,26 @@ def main(server, command, program, action, firstline, fileLog, logLevel, show_lo format='%(asctime)s %(levelname)s [pid:%(process)d] [%(funcName)s:%(lineno)d] %(message)s') # Send command if command == 'START' or command == 'STOP': - send_json({'name': program}, 'POST', "/" + command, server, port) + send_json({'name': program}, 'POST', "/" + command, host, port, key_file=key_file, + cert_file=cert_file, ca_cert=ca_cert) elif command == 'STATUS': - send_json({'name': program}, 'GET', "/" + command, server, port) + send_json({'name': program}, 'GET', "/" + command, host, port, key_file=key_file, + cert_file=cert_file, ca_cert=ca_cert) elif command == 'ACTION': - send_json({'name': program, 'action' : action}, 'POST', "/" + command, server, port) + send_json({'name': program, 'action' : action}, 'POST', "/" + command, host, port, + key_file=key_file, cert_file=cert_file, ca_cert=ca_cert) elif command == 'LOG': - send_json({'name': program, 'first-line' : firstline }, 'GET', "/" + command, server, port, raw_data, remove_color) + send_json({'name': program, 'first-line' : firstline }, 'GET', "/" + command, host, port, raw_data, + remove_color, key_file=key_file, cert_file=cert_file, ca_cert=ca_cert) elif command == 'LIST': - send_json({}, 'GET', "/" + command, server, port) + send_json({}, 'GET', "/" + command, host, port, key_file=key_file, + cert_file=cert_file, ca_cert=ca_cert) elif command == 'SHUTDOWN' or command == 'STARTALL' or command == 'STOPALL': - send_json({}, 'POST', "/" + command, server, port) + send_json({}, 'POST', "/" + command, host, port, key_file=key_file, + cert_file=cert_file, ca_cert=ca_cert) elif command == 'STATUSALL': - send_json({}, 'GET', "/" + command, server, port) + send_json({}, 'GET', "/" + command, host, port, key_file=key_file, + cert_file=cert_file, ca_cert=ca_cert) else: logging.error("command unknown (%s)" % command) @@ -170,7 +217,8 @@ if __name__ == '__main__': default='INFO', help='log level [DEBUG, INFO, WARNING, ERROR') parser.add_argument('--key', help='key file', default=None) parser.add_argument('--cert', help='cert file', default=None) - parser.add_argument('--server', help='server khganat', default='127.0.0.1') + parser.add_argument('--ca_cert', help='ca_cert file', default=None) + parser.add_argument('--host', help='server khganat', default='127.0.0.1') parser.add_argument('--command', help='command send to khganat', default='/STATUS') parser.add_argument('--program', help='program khaganat id ', default='aes') parser.add_argument('--action', help='action ', default='') @@ -181,9 +229,9 @@ if __name__ == '__main__': parser.add_argument( '--keep-color', action='store_true', help='some message have color define, by default we reset the color (this option keep current color state)', default=False) args = parser.parse_args() - main(server = args.server, action = args.action, firstline = args.firstline, + main(host = args.host, action = args.action, firstline = args.firstline, command = args.command, program = args.program, fileLog = args.filelog, logLevel=args.log, show_log_console=args.show_log_console, raw_data = args.raw_data, - key_file=args.key, cert_file=args.cert, + key_file=args.key, cert_file=args.cert, ca_cert=args.ca_cert, remove_color=not args.keep_color) diff --git a/code/khaganat/tools/create_certificate.py b/code/khaganat/tools/create_certificate.py new file mode 100755 index 000000000..79474228d --- /dev/null +++ b/code/khaganat/tools/create_certificate.py @@ -0,0 +1,422 @@ +#!/usr/bin/python3 +# +# script to create certificate use for test +# +# Copyright (C) 2017 AleaJactaEst +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Generate all certificates + CA certificate (emulate CA certificate) + Appli certification (our global certificate, use to sign our key) + Server certificate (our key & certificate for server side) + Client certificate (our key & certificate for server side) + + CA + \ + Apppli + / \ + Server Client + +Example command to generate all certificate : + create_certificate.py --show-log-console --log debug +""" + +import argparse +import logging +import logging.config +import os +import stat +import subprocess +import sys + + +class Certificate: + def __init__(self, + openssl, + workdir_cert_ca, + workdir_cert_appli, + passca='OpenNelCA9439', + passappli='OpenNelAPPLI1097', + countryName='FR', + stateOrProvinceName='France', + localityName='Paris', + organizationName='khanat', + commonName='khanat.org', + sizeCa = 4096, + sizeAppli = 4096, + sizeChild = 2048): + self.workdir_cert_ca = os.path.abspath(workdir_cert_ca) + self.workdir_cert_appli = os.path.abspath(workdir_cert_appli) + self.openssl = openssl + self.passca = passca + self.passappli = passappli + self.countryName = countryName + self.stateOrProvinceName = stateOrProvinceName + self.localityName = localityName + self.organizationName = organizationName + self.commonName = commonName + self.configca = os.path.join(self.workdir_cert_ca, 'openssl.cnf') + self.configappli = os.path.join(self.workdir_cert_appli, 'openssl.cnf') + self.sizeCa = sizeCa + self.sizeAppli = sizeAppli + self.sizeChild = sizeChild + + def directory_create(self, dirpath): + if not dir: + raise ValueError + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + def SendCommandOpenssl(self, args): + command = '%s %s' % (self.openssl, args) + logging.debug("command:%s" % command) + code = subprocess.call(command.split(), stdout=sys.stdout, + stderr=sys.stderr) + if code != 0: + logging.error("Command '%s' return code:%d" % (command, code)) + exit(code) + + def writeConfigOpenssl(self, config, dirpath, certfile, keyfile): + with open(config, 'w') as f: + f.write('[ ca ]\n' + 'default_ca = CA_default\n' + '\n[ CA_default ]\n' + 'dir = %s\n' + 'certs = $dir/certs\n' + 'crl_dir = $dir/crl\n' + 'database = $dir/index.txt\n' + 'new_certs_dir = $dir/newcerts\n' + 'certificate = $dir/certs/%s\n' + 'serial = $dir/serial\n' + 'crlnumber = $dir/crlnumber\n' + 'crl = $dir/crl/%s\n' + 'private_key = $dir/private/%s\n' + 'RANDFILE = $dir/private/.rand\n' + 'name_opt = ca_default\n' + 'cert_opt = ca_default\n' + 'default_days = 390\n' + 'default_crl_days = 30\n' + 'default_md = sha256\n' + 'preserve = no\n' + 'policy = policy_match\n' + 'crl_extensions = crl_ext\n' + 'unique_subject = no\n' + '\n[ policy_match ]\n' + 'countryName = match\n' + 'stateOrProvinceName = match\n' + 'organizationName = match\n' + 'organizationalUnitName = optional\n' + 'commonName = supplied\n' + 'emailAddress = optional\n' + '\n[ req ]\n' + 'default_bits = 2048\n' + 'distinguished_name = req_distinguished_name\n' + 'x509_extensions = v3_ca\n' + 'string_mask = utf8only\n' + 'unique_subject = no\n' + '\n[ server_cert ]\n' + 'basicConstraints=CA:false\n' + 'nsComment = "OpenSSL Generated Certificate"\n' + 'subjectKeyIdentifier=hash\n' + 'authorityKeyIdentifier=keyid,issuer:always\n' + 'keyUsage = critical, digitalSignature, keyEncipherment\n' + 'nsCertType = server\n' + '\n[ client_cert ]\n' + 'basicConstraints=CA:false\n' + 'nsComment = "OpenSSL Generated Certificate"\n' + 'subjectKeyIdentifier=hash\n' + 'authorityKeyIdentifier=keyid:always,issuer\n' + 'keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment\n' + 'nsCertType = client\n' + '\n[ v3_ca ]\n' + 'basicConstraints=critical, CA:true\n' + 'nsComment = "OpenSSL Generated Certificate"\n' + 'subjectKeyIdentifier=hash\n' + 'authorityKeyIdentifier=keyid:always,issuer\n' + 'keyUsage = critical, digitalSignature, cRLSign, keyCertSign\n' + '\n[ v3_application_ca ]\n' + 'basicConstraints=critical, CA:true, pathlen:0\n' + 'nsComment = "OpenSSL Generated Certificate"\n' + 'subjectKeyIdentifier=hash\n' + 'authorityKeyIdentifier=keyid:always,issuer\n' + 'keyUsage = critical, digitalSignature, cRLSign, keyCertSign\n' + '\n[ req_distinguished_name ]\n' + 'countryName = Country Name (2 letter code)\n' + 'countryName_default = FR\n' + 'countryName_min = 2\n' + 'countryName_max = 2\n' + 'stateOrProvinceName = State or Province Name (full name)\n' + 'stateOrProvinceName_default = France\n' + 'localityName = Locality Name (eg, city)\n' + '0.organizationName = Organization Name (eg, company)\n' + '0.organizationName_default = Khanat\n' + 'organizationalUnitName = Organizational Unit Name (eg, section)\n' + 'commonName = Common Name (e.g. server FQDN or YOUR name)\n' + 'commonName_max = 64\n' + 'emailAddress = Email Address\n' + 'emailAddress_max = 64\n' + '\n[ crl_ext ]\n' + 'authorityKeyIdentifier=keyid:always\n' + % (dirpath, certfile, 'cacrl.pem', keyfile)) + + def createCACertificate(self): + logging.info("Create CA Certificate") + # Create directory + certfilename = 'cacert.pem' + keyfilename = 'cakey.pem' + self.directory_create(self.workdir_cert_ca) + self.directory_create(os.path.join(self.workdir_cert_ca, 'certs')) + private=os.path.join(self.workdir_cert_ca, 'private') + self.directory_create(private) + os.chmod(private, stat.S_IEXEC | stat.S_IWUSR | stat.S_IRUSR) + self.directory_create(os.path.join(self.workdir_cert_ca, 'crl')) + self.directory_create(os.path.join(self.workdir_cert_ca, 'newcerts')) + # Create files use in CA + index = os.path.join(self.workdir_cert_ca, 'index.txt') + with open(index, 'w') as f: + f.write('') + serial = os.path.join(self.workdir_cert_ca, 'serial') + with open(serial, 'w') as f: + f.write('10') + # Create configuration + self.writeConfigOpenssl(self.configca, self.workdir_cert_ca, certfilename, keyfilename) + # Create private key for our CA + keyfile = os.path.join(self.workdir_cert_ca, 'private', keyfilename) + self.SendCommandOpenssl('genrsa -aes256 -out %s -passout pass:%s %d' % (keyfile, self.passca, self.sizeCa)) + os.chmod(keyfile, stat.S_IEXEC | stat.S_IWUSR | stat.S_IRUSR) + # Create certificate for our CA + certfile = os.path.join(self.workdir_cert_ca, 'certs', certfilename) + self.SendCommandOpenssl('req ' + '-config %s ' + '-key %s ' + '-passin pass:%s ' + '-new ' + '-x509 ' + '-days 390 ' + '-sha256 ' + '-extensions v3_ca ' + '-out %s ' + '-subj /C=%s/ST=%s/L=%s/O=%s/CN=%s' % (self.configca, + keyfile, + self.passca, + certfile, + self.countryName, + self.stateOrProvinceName, + self.localityName, + self.organizationName, + self.commonName)) + os.chmod(certfile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) + + # Check certificate + self.SendCommandOpenssl('x509 -noout -text -in %s' % certfile) + + def createApplicationCertificate(self): + logging.info("Create Application Certificate") + certfilename = 'applicert.pem' + csrfilename = 'applicsr.pem' + keyfilename = 'applikey.pem' + # Create directory + self.directory_create(self.workdir_cert_appli) + self.directory_create(os.path.join(self.workdir_cert_appli, 'certs')) + private=os.path.join(self.workdir_cert_appli, 'private') + self.directory_create(private) + os.chmod(private, stat.S_IEXEC | stat.S_IWUSR | stat.S_IRUSR) + self.directory_create(os.path.join(self.workdir_cert_appli, 'crl')) + self.directory_create(os.path.join(self.workdir_cert_appli, 'newcerts')) + self.directory_create(os.path.join(self.workdir_cert_appli, 'csr')) + # Create files use in CA + index = os.path.join(self.workdir_cert_appli, 'index.txt') + with open(index, 'w') as f: + f.write('') + serial = os.path.join(self.workdir_cert_appli, 'serial') + with open(serial, 'w') as f: + f.write('10') + serial = os.path.join(self.workdir_cert_appli, 'crlnumber') + with open(serial, 'w') as f: + f.write('10') + # Create configuration + self.writeConfigOpenssl(self.configappli, self.workdir_cert_appli, certfilename, keyfilename) + # Create private key for our Application + keyfile = os.path.join(self.workdir_cert_appli, 'private', keyfilename) + self.SendCommandOpenssl('genrsa -aes256 -out %s -passout pass:%s %d' % (keyfile, + self.passappli, + self.sizeAppli)) + os.chmod(keyfile, stat.S_IEXEC | stat.S_IWUSR | stat.S_IRUSR) + # Create certificate for our CA + csrfile = os.path.join(self.workdir_cert_appli, 'csr', csrfilename) + self.SendCommandOpenssl('req ' + '-config %s ' + '-new ' + '-sha256 ' + '-passin pass:%s ' + '-key %s ' + '-out %s ' + '-subj /C=%s/ST=%s/L=%s/O=%s/CN=%s' % (self.configappli, + self.passappli, + keyfile, + csrfile, + self.countryName, + self.stateOrProvinceName, + self.localityName, + self.organizationName, + self.commonName)) + os.chmod(csrfile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) + certfile = os.path.join(self.workdir_cert_appli, 'certs', certfilename) + self.SendCommandOpenssl('ca ' + '-config %s ' + '-extensions v3_application_ca ' + '-days 390 ' + '-notext ' + '-md sha256 ' + '-passin pass:%s ' + '-in %s ' + '-batch ' + '-out %s ' % (self.configca, + self.passca, + csrfile, + certfile)) + os.chmod(csrfile, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) + self.SendCommandOpenssl('x509 -noout -text -in %s' % certfile) + certcafilename = os.path.join(self.workdir_cert_ca, 'certs', 'cacert.pem') + self.SendCommandOpenssl('verify -CAfile %s %s' % (certcafilename, certfile)) + # concat applicert & cacert + cachainfile = os.path.join(self.workdir_cert_appli, 'certs', 'cachaincert.pem') + with open(cachainfile, 'w') as outfp: + with open(certfile, 'r') as infp: + outfp.write(infp.read()) + with open(certcafilename, 'r') as infp: + outfp.write(infp.read()) + + def createChildCertificate(self, childname, extension): + keyfilename = "%skey.pem" % childname + csrfilename = "%scsr.pem" % childname + certfilename = "%scert.pem" % childname + keyfile = os.path.join(self.workdir_cert_appli, 'private', keyfilename) + self.SendCommandOpenssl('genrsa -out %s %d' % (keyfile, self.sizeChild)) + csrfile = os.path.join(self.workdir_cert_appli, 'csr', csrfilename) + self.SendCommandOpenssl('req ' + '-config %s ' + '-new ' + '-sha256 ' + '-key %s ' + '-out %s ' + '-subj /C=%s/ST=%s/L=%s/O=%s/CN=%s' % (self.configappli, + keyfile, + csrfile, + self.countryName, + self.stateOrProvinceName, + self.localityName, + self.organizationName, + self.commonName)) + certfile = os.path.join(self.workdir_cert_appli, 'certs', certfilename) + self.SendCommandOpenssl('ca ' + '-config %s ' + '-extensions %s ' + '-days 390 ' + '-notext ' + '-md sha256 ' + '-passin pass:%s ' + '-in %s ' + '-batch ' + '-out %s ' % (self.configappli, + extension, + self.passappli, + csrfile, + certfile)) + self.SendCommandOpenssl('x509 -noout -text -in %s' % (certfile)) + certcafilename = os.path.join(self.workdir_cert_appli, 'certs', 'cachaincert.pem') + self.SendCommandOpenssl('verify -CAfile %s %s' % (certcafilename, certfile)) + + +def main(fileLog, logLevel, show_log_console, + workdir_cert_ca, workdir_cert_appli, openssl, + sizeCa, sizeAppli, sizeChild, + passca, passappli, + countryName, stateOrProvinceName, localityName, organizationName, commonName): + """ Main function """ + # Manage log + logging.getLogger('logging') + numeric_level = getattr(logging, logLevel.upper(), None) + if not isinstance(numeric_level, int): + raise ValueError('Invalid log level: %s' % logLevel) + handlers=[] + if show_log_console: + handlers.append(logging.StreamHandler()) + if fileLog: + handlers.append(logging.FileHandler(fileLog.name)) + logging.basicConfig(handlers=handlers, level=numeric_level, + format='%(asctime)s %(levelname)s [pid:%(process)d] [%(funcName)s:%(lineno)d] %(message)s') + + certicate = Certificate(openssl, workdir_cert_ca, workdir_cert_appli, + passca, passappli, + countryName, + stateOrProvinceName, + localityName, + organizationName, + commonName, + sizeCa, + sizeAppli , + sizeChild) + logging.info("Generate CA certificate") + certicate.createCACertificate() + logging.info("Generate Application certificate") + certicate.createApplicationCertificate() + logging.info("Generate Server certificate") + certicate.createChildCertificate('server', 'server_cert') + logging.info("Generate Client certificate") + certicate.createChildCertificate('client', 'client_cert') + logging.info("Certifcate generated") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Create certificate') + parser.add_argument('--version', action='version', version='%(prog)s 1.0') + parser.add_argument( '--openssl', default='openssl', help='binary openssl') + parser.add_argument('-c', '--workdir-cert-ca', default='ca', help='workdir certificate CA') + parser.add_argument('-a', '--workdir-cert-appli', default='ca/appli', help='workdir certificate Application') + parser.add_argument( '--show-log-console', action='store_true', + help='show message in console', default=False) + parser.add_argument('--filelog', type=argparse.FileType('wt'), + default=None, help='log file') + parser.add_argument('--log', + default='INFO', help='log level [DEBUG, INFO, WARNING, ERROR') + parser.add_argument('--sizeCa', type=int, default=4096, help='Define size key for CA certificate') + parser.add_argument('--sizeAppli', type=int, default=4096, help='Define size key for Application certificate') + parser.add_argument('--sizeChild', type=int, default=4096, help='Define size key for Child certificate') + parser.add_argument('--passca', default='OpenNelCA9439', help='define password for CA certificate') + parser.add_argument('--passappli', default='OpenNelAPPLI1097', help='define password for Application certificate') + parser.add_argument('--countryName', default='FR', help='countryName for certicate') + parser.add_argument('--stateOrProvinceName', default='France', help='stateOrProvinceName for certicate') + parser.add_argument('--localityName', default='Paris', help='localityName for certicate') + parser.add_argument('--organizationName', default='khanat', help='organizationName for certicate') + parser.add_argument('--commonName', default='khanat', help='commonName for certicate') + args = parser.parse_args() + main(fileLog = args.filelog, + logLevel = args.log, + show_log_console = args.show_log_console, + workdir_cert_ca = args.workdir_cert_ca, + workdir_cert_appli = args.workdir_cert_appli, + openssl = args.openssl, + sizeCa = args.sizeCa, + sizeAppli = args.sizeAppli, + sizeChild = args.sizeChild, + passca = args.passca, + passappli = args.passappli, + countryName = args.countryName, + stateOrProvinceName = args.stateOrProvinceName, + localityName = args.localityName, + organizationName = args.organizationName, + commonName = args.commonName) diff --git a/code/khaganat/tools/khaganat.cfg b/code/khaganat/tools/khaganat.cfg index 3e8a0aedf..9f0b8f061 100644 --- a/code/khaganat/tools/khaganat.cfg +++ b/code/khaganat/tools/khaganat.cfg @@ -21,7 +21,7 @@ # Global parameter ############################## ############################## -[config] +[manage] # Define port listen (default 8000) port = 8000 @@ -29,10 +29,13 @@ port = 8000 # openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -subj "/C=FR/ST=France/L=Paris/O=khaganat/CN=khaganat.org" # key -keyfile = /home/gameserver/khanat/key.pem +keyfile = /home/gameserver/ca/appli/private/serverkey.pem # certificate -certfile = /home/gameserver/khanat/cert.pem +certfile = /home/gameserver/ca/appli/certs/servercert.pem + +# certification to check signature +ca_cert = /home/gameserver/ca/appli/certs/cachaincert.pem # address listen (default all port) address = diff --git a/code/khaganat/tools/manage.py b/code/khaganat/tools/manager.py similarity index 93% rename from code/khaganat/tools/manage.py rename to code/khaganat/tools/manager.py index 70913df3f..63dc4a781 100755 --- a/code/khaganat/tools/manage.py +++ b/code/khaganat/tools/manager.py @@ -43,19 +43,22 @@ Design Configuration File : This script need configuration file (see below for model) ------------------------------------------------------------------------------ -[config] +[manager] # Define port listen (default 8000) port = 8000 # Generate key # openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -subj "/C=FR/ST=France/L=Paris/O=khaganat/CN=khaganat.org" -# key +# your key keyfile = crt/key.pem -# certificate +# your certificate certfile = crt/cert.pem +# certification to check signature +ca_cert = /home/gameserver/ca/appli/certs/cachaincert.pem + # address listen (default all port) address = @@ -401,14 +404,15 @@ class ServerHttp(multiprocessing.Process): Initialize server HTTPS * define Dictionnary queueIn & queueOut (with key as section's name in configuration) """ - def __init__(self, keyfile, certfile, address = '', port=8000): + def __init__(self, keyfile, certfile, ca_cert, address = '', port=8000): multiprocessing.Process.__init__(self) self.listQueueIn = {} self.listQueueOut = {} self.listEvent = {} self.port = port - self.keyfile = keyfile - self.certfile = certfile + self.key_file = keyfile + self.cert_file = certfile + self.ca_cert = ca_cert self.address = address def run(self): @@ -418,11 +422,20 @@ class ServerHttp(multiprocessing.Process): self.listEvent, server_address, ManageHttpRequest) - httpd.socket = ssl.wrap_socket (httpd.socket, - keyfile = self.keyfile, - certfile = self.certfile, - ca_certs=None, + if self.ca_cert: + httpd.socket = ssl.wrap_socket(httpd.socket, + keyfile = self.key_file, + certfile = self.cert_file, + ca_certs = self.ca_cert, + cert_reqs = ssl.CERT_REQUIRED, + ssl_version=ssl.PROTOCOL_TLSv1_2, + server_side = True) + else: + httpd.socket = ssl.wrap_socket (httpd.socket, + keyfile = self.key_file, + certfile = self.cert_file, server_side = True) + logging.info('https listen') httpd.serve_forever() def append(self, name, queueIn, queueOut, event): @@ -460,9 +473,19 @@ class ManageCommand(): """ Thread to read output (stdout) """ fl = fcntl.fcntl(self.process.stdout, fcntl.F_GETFL) fcntl.fcntl(self.process.stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK) - logging.debug("Start reader %s " % self.name) + logging.debug("Start reader %s" % self.name) while self.eventRunning.is_set(): - line = self.process.stdout.readline() + code = self.process.poll() + if code is not None: + logging.error("process %s down" % self.name) + self.eventRunning.clear() + continue + try: + line = self.process.stdout.readline() + except AttributeError: + logging.error("process %s down (not detected)" % self.name) + self.eventRunning.clear() + continue if not line: time.sleep(1) continue @@ -676,21 +699,25 @@ class Manager(): if name == 'config': logging.debug("read config '%s'" % name) try: - port = int(config[name]['port']) + self.port = int(config[name]['port']) except (TypeError, KeyError, ValueError): - port = 8000 + self.port = 8000 try: - address = config[name]['address'] + self.address = config[name]['address'] except (TypeError, KeyError): - address = '' + self.address = '' try: - keyfile = config[name]['keyfile'] + self.keyfile = config[name]['keyfile'] except (TypeError, KeyError): - keyfile = 'crt/key.pem' + self.keyfile = 'crt/key.pem' try: - certfile = config[name]['certfile'] + self.certfile = config[name]['certfile'] except (TypeError, KeyError): - certfile = 'crt/cert.pem' + self.certfile = 'crt/cert.pem' + try: + self.ca_cert = config[name]['ca_cert'] + except (TypeError, KeyError): + self.ca_cert = 'crt/ca_cert.crt' elif 'command' in config[name]: logging.debug("read command '%s'" % name) if 'path' in config[name]: @@ -715,7 +742,7 @@ class Manager(): bufsize = 100 self.param.setdefault(name, {'command': config[name]['command'], 'path': path, 'logsize': logsize, 'bufsize': bufsize}) - self.serverHttp = ServerHttp(keyfile, certfile, address, port) + self.serverHttp = ServerHttp(self.keyfile, self.certfile, self.ca_cert, self.address, self.port) if filecfg is None: raise ValueError diff --git a/dist/docker/server/debian/common/khaganat.cfg b/dist/docker/server/debian/common/khaganat.cfg index 3e8a0aedf..f0c8c5201 100644 --- a/dist/docker/server/debian/common/khaganat.cfg +++ b/dist/docker/server/debian/common/khaganat.cfg @@ -29,10 +29,13 @@ port = 8000 # openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -subj "/C=FR/ST=France/L=Paris/O=khaganat/CN=khaganat.org" # key -keyfile = /home/gameserver/khanat/key.pem +keyfile = /home/gameserver/ca/appli/private/serverkey.pem # certificate -certfile = /home/gameserver/khanat/cert.pem +certfile = /home/gameserver/ca/appli/certs/servercert.pem + +# certification to check signature +ca_cert = /home/gameserver/ca/appli/certs/cachaincert.pem # address listen (default all port) address =