khanat-code-old/code/khaganat/tools/create_certificate.py
2017-11-13 21:18:48 +01:00

422 lines
21 KiB
Python
Executable file

#!/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 <http://www.gnu.org/licenses/>.
"""
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)