#!/usr/bin/python3 #------------------------------------------------------------------------------- # Name: Samba PKI Tools # Purpose: # # Author: kguerineau-adm # # Created: 10/05/2024 # Copyright: (c) kguerineau-adm 2024 # Licence: #------------------------------------------------------------------------------- # Maange Intermediate CA from common import Printing, TisPKI, check_directories, config from root_module import generate_root_crl import subprocess import jinja2 import os import configparser import sys from colorama import Fore, Style import shutil import time import glob def create_openssl_intermediate(name, force=False, verbose=False): ## if force: ## Printing.error("Do you realy want to remove ALL you PKI ? This will destroy ALL YOUR CERTIFICATES AND PRIVATE KEY") ## Printing.error("After that, you MUST REGENERATE YOUR PKI with NEW certificates and private key for ALL YOUR DOMAIN CONTROLLERS AND USERS") ## destroy = input('If you are realy sure, please enter : "I want to remove all my PKI" : ') ## if destroy == 'I want to remove all my PKI': ## Printing.information('OK, too late ! Destroying your PKI !') ## time.sleep(1) ## shutil.rmtree(TisPKI.pki_dir(), ignore_errors=True) Printing.information(f'Create intermediate CA {name}') check_directories(path=TisPKI.pki_intermediate_dir(name),verbose=verbose) intermediate_ca_config = os.path.join(TisPKI.intermediate_config_path(name),'create_intermediate_ca.ini') intermediate_crl_file = os.path.join(TisPKI.intermediate_crl_path(name),f'{name}_intermediate_ca.crl') root_ca_sign_intermediate = os.path.join(TisPKI.root_config_path(),'openssl_root_ca_sign_intermediate.ini') if not os.path.isfile(root_ca_sign_intermediate): if TisPKI.intermediate_ca: template_dir = os.path.join('templates') jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir)) root_ca_tmpl = jinja_env.get_template('openssl_sign_intermediate_csr.tmpl') root_ca_tmpl_var = { 'organization_ou': config.get('openssl_config','organization_name') + ' CA', 'pki_dir': TisPKI.pki_dir(), 'root_ca_keyfile': TisPKI.root_ca_keyfile(), 'root_ca_certfile': TisPKI.root_ca_certfile(), 'intermediate_crl_uri': config.get('openssl_config','intermediate_crl_uri'), 'default_crl_duration' : config.get('openssl_config','default_crl_duration'), } config_string = root_ca_tmpl.render(root_ca_tmpl_var) with open(root_ca_sign_intermediate,'wt') as file: file.write(config_string) if os.path.isfile(root_ca_sign_intermediate): Printing.success('Root CA OpenSSL sign intermediate config file is correctly generated !') if not os.path.isfile(intermediate_ca_config): Printing.information('Intermediate CA OpenSSL configfile not exist. Creating...') template_dir = os.path.join('templates') jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir)) intermediate_ca_tmpl = jinja_env.get_template('openssl_create_intermediate_ca.tmpl') intermediate_ca_tmpl_var = { 'country': config.get('openssl_config','country'), 'state': config.get('openssl_config','state'), 'city': config.get('openssl_config','city'), 'organization_name': config.get('openssl_config','organization_name'), 'organization_ou': config.get('openssl_config','organization_ou'), 'intermediate_organization_cn': name, 'intermediate_crl_uri': config.get('openssl_config','intermediate_crl_uri') } config_string = intermediate_ca_tmpl.render(intermediate_ca_tmpl_var) with open(intermediate_ca_config,'wt') as file: file.write(config_string) if os.path.isfile(intermediate_ca_config): Printing.success('Intermediate CA OpenSSL configfile is correctly generated !') else: Printing.information('Intermediate CA OpenSSL config already exist. Skip.') if not os.path.isfile(TisPKI.intermediate_ca_keyfile(name)) and not os.path.isfile(TisPKI.intermediate_ca_certfile(name)): Printing.information('Generate Intermediate CA private key and CSR') gen_intermediate_ca = subprocess.run(f"/usr/bin/openssl req -config {intermediate_ca_config} -new -sha512 -keyout {TisPKI.intermediate_ca_keyfile(name)} \ -out {TisPKI.intermediate_csr_path(name)}/{name.replace(' ','_')}_intermediate_ca.csr", shell=True, check=False, executable='/bin/bash') if gen_intermediate_ca.returncode == 0: Printing.information('Sign Intermediate CA with Root CA') sign_intermediate_ca = subprocess.run(f"/usr/bin/openssl ca -config {os.path.join(TisPKI.root_config_path(),'openssl_root_ca_sign_intermediate.ini')} \ -extensions v3_intermediate_ca -days 1825 -notext -md sha512 -create_serial -in {TisPKI.intermediate_csr_path(name)}/{name.replace(' ','_')}_intermediate_ca.csr \ -out {TisPKI.intermediate_ca_certfile(name)}", shell=True, check=False, executable='/bin/bash') if sign_intermediate_ca.returncode == 0: if verbose: subprocess.run(f'openssl x509 -in {TisPKI.intermediate_ca_certfile(name)} -text', shell=True, check=True, executable='/bin/bash') Printing.success(f'Intermediate CA Certfile is stored in : {TisPKI.intermediate_ca_certfile(name)}') else: Printing.error('Error on generating Intermediate CA private key') retry = input('If you want to retry, press Y : ') if retry == "y" or retry == 'Y': os.remove(TisPKI.intermediate_ca_keyfile(name)) create_openssl_intermediate(name, force, verbose) else: Printing.error('Error on generating Intermediate CA private key') retry = input('If you want to retry, press Y : ') if retry == "y" or retry == 'Y': os.remove(TisPKI.intermediate_ca_keyfile(name)) create_openssl_intermediate(name, force, verbose) else: Printing.warning('Intermediate CA private key and certificate already exist. Skip.') def generate_intermediate_crl(configfile=None, ca_name=None, verbose=False): Printing.information(f'Generate CRL for {ca_name} intermediate CA') if configfile==None: for file in glob.glob(os.path.join(TisPKI.intermediate_config_path(ca_name),'openssl_*.ini')): configfile = file break gen_crl = subprocess.run(f'openssl ca -config {configfile} -gencrl -out {TisPKI.intermediate_ca_crlfile(ca_name)}',shell=True) if gen_crl.returncode == 0: if verbose: subprocess.run(f'openssl crl -in {TisPKI.intermediate_ca_crlfile(ca_name)} -text') Printing.success(f'CRL successfuly generated in : {TisPKI.intermediate_ca_crlfile(ca_name)}') else: Printing.error('Unable to generate CRL') def list_ca_certificates(ca_name=None): Printing.information(f'List certificates issued of {ca_name}') certs_list = [] try: with open(os.path.join('/opt',TisPKI.pki_intermediate_dir(ca_name),'index.txt'),'r') as index: for line in index.readlines(): if line.split('\t')[0] == 'R': status = 'Revoked' elif line.split('\t')[0] == 'V': status = 'Valid ' elif line.split('\t')[0] == 'E': status = 'Expired' else: status = line.split('\t')[0] serial_number = line.split('\t')[3] exp_date = line.split('\t')[1] expiration_date = '20' + exp_date[0:2] + '/' + exp_date[2:4] + '/' + exp_date[4:6] + ' ' + exp_date[6:8] + ':' + exp_date[8:10] +':'+ exp_date[10:12] rev_date = line.split('\t')[2] if rev_date != '': revocation_date = '20' + rev_date[0:2] + '/' + rev_date[2:4] + '/' + rev_date[4:6] + ' ' + rev_date[6:8] + ':' + rev_date[8:10] +':'+ rev_date[10:12] else: revocation_date = ' ' cn = line.split('\t')[5].split('CN')[1].replace('=','').replace('\n','') cn_len = 20 if len(cn) < cn_len: diff = cn_len - len(cn) space = '' for i in range(0, diff): space = space + ' ' commonName = cn + space commonName_full = '' else: commonName = cn[0:20] commonName_full = cn certs_list.append(commonName + ' | ' + status + ' | ' + serial_number + ' | ' + expiration_date + ' | ' + revocation_date + ' | ' + commonName_full) print(' CommonName | Status | Serial Number | Expiration date | Revocation date |') print('---------------------|---------|------------------------------------------|---------------------|---------------------|') for cert in certs_list: print(cert) except Exception as e: if "Errno 2" in str(e): Printing.error('Unable to find CA') else: Printing.error('Error when list certificates %s' % e)