#!/usr/bin/env python3
# ==========================================================================
#         ____            _                     _____           _
#        / ___| _   _ ___| |_ ___ _ __ ___     |_   _|__   ___ | |___
#        \___ \| | | / __| __/ _ \ '_ ` _ \ _____| |/ _ \ / _ \| / __|
#         ___) | |_| \__ \ ||  __/ | | | | |_____| | (_) | (_) | \__ \
#        |____/ \__, |___/\__\___|_| |_| |_|     |_|\___/ \___/|_|___/
#               |___/
#                             --- System-Tools ---
#                  https://www.nntb.no/~dreibh/system-tools/
# ==========================================================================
#
# X.509 CA and Certificate Test Setup Script
# Copyright (C) 2015-2025 by Thomas Dreibholz
#
# 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/>.
#
# Contact: thomas.dreibholz@gmail.com

import sys

from CertificateHelper import *


# ###### Main program #######################################################

# ====== Handle command-line parameters =====================================
if len(sys.argv) < 3:
   sys.stderr.write('Usage: ' + sys.argv[0] + ' ssl_directory [--server|--client|--user] [--revoke-if-existing|--ignore-if-existing] [--revoke] [--san subjectAltName|LOCAL|LOOKUP] name ...\n')
   sys.exit(1)
mainDirectory        : str                 = sys.argv[1]
certificatesToCreate : list[dict[str,str]] = []
subjectAltName       : str | None          = None
certType             : CertificateType     = CertificateType.Server
revokeIfExisting     : bool                = True
revoke               : bool                = False
i = 2
while i < len(sys.argv):
   if sys.argv[i] == '--server':
      certType = CertificateType.Server
   elif sys.argv[i] == '--client':
      certType = CertificateType.Client
   elif sys.argv[i] == '--user':
      certType = CertificateType.User
   elif sys.argv[i] == '--revoke':
      revoke = True
   elif sys.argv[i] == '--revoke-if-existing':
      revokeIfExisting = True
   elif sys.argv[i] == '--ignore-if-existing':
      revokeIfExisting = False
   elif (sys.argv[i] == '--san') or (sys.argv[i] == '--subjectAltName'):
      if i + 1 < len(sys.argv[i + 1]):
         subjectAltName = sys.argv[i + 1]
         i += 1
   elif sys.argv[i][0:2] == '--':
      sys.stderr.write('ERROR: Invalid parameter ' + sys.argv[i] + '!\n')
      sys.exit(1)
   else:
      ( name,  san ) = prepareSubjectAltName(certType, sys.argv[i], subjectAltName)
      certificatesToCreate.append({ 'name'             : name,
                                    'type'             : certType,
                                    'subjectAltName'   : san,
                                    'revokeIfExisting' : revokeIfExisting })
   i += 1


# ====== Create CA hierarchy, if not existing ===============================

# ===========================================================================
# Hierarchy to be created:
# TestLevel1
#    - TestLevel2
#       - TestIntermediate
#          - TestLeaf
#             - Servers ...
#          - TestCA
#             - TestUserCA
#                - Users ...
#             - TestServerCA
#                - Servers ...
# ===========================================================================


# ====== Create Test CAs ====================================================
caKeyLength       = DefaultCAKeyLength
certKeyLength     = DefaultCertKeyLength
globalCRLFileName = "TestGlobal.crl"

# Create Test Root Level-1 CA certificate (self-signed):
TestLevel1 = CA(mainDirectory, 'TestLevel1',
                parentCA  = None,
                subject   = '/C=NO/ST=Oslo/L=Oslo/O=Simula Research Laboratory/streetAddress=Kristian Augusts gate 23/postalCode=0164/CN=Test Level-1 CA Certificate',
                certType  = CertificateType.RootCA,
                keyLength = caKeyLength, globalCRLFileName = globalCRLFileName)

# Create Test Root Level-2 CA certificate (signed by Test Root Level-1):
TestLevel2 = CA(mainDirectory, 'TestLevel2',
                parentCA  = TestLevel1,
                subject   = '/C=NO/ST=Oslo/L=Oslo/O=Simula Research Laboratory/streetAddress=Kristian Augusts gate 23/postalCode=0164/CN=Test Level-2 CA Certificate',
                certType  = CertificateType.IntermediateCA,
                keyLength = caKeyLength, globalCRLFileName = globalCRLFileName)

# Create Test Intermediate CA certificate (signed by Test Root Level-2):
TestIntermediate1 = CA(mainDirectory, 'TestIntermediate1',
                       parentCA  = TestLevel2,
                       subject   = '/C=NO/ST=Oslo/L=Oslo/O=Simula Metropolitan Centre for Digital Engineering (SimulaMet)/streetAddress=Stensberggata 27/postalCode=0170/CN=*',
                       certType  = CertificateType.IntermediateCA,
                       keyLength = caKeyLength, globalCRLFileName = globalCRLFileName)

# Create Test Intermediate CA certificate (signed by Test Root Level-2):
TestIntermediate2 = CA(mainDirectory, 'TestIntermediate2',
                       parentCA  = TestIntermediate1,
                       subject   = '/C=NO/ST=Oslo/L=Oslo/O=Simula Metropolitan Centre for Digital Engineering (SimulaMet)/OU=Centre for Resilient Networks and Applications (CRNA)/streetAddress=Stensberggata 27/postalCode=0170/CN=*',
                       certType  = CertificateType.IntermediateCA,
                       keyLength = caKeyLength, globalCRLFileName = globalCRLFileName)

# Create Test Leaf CA certificate (signed by Test Intermediate):
TestLeaf = CA(mainDirectory, 'TestLeaf',
              parentCA  = TestIntermediate2,
              subject   = '/C=NO/ST=Oslo/L=Oslo/O=Simula Metropolitan Centre for Digital Engineering (SimulaMet)/OU=SimulaMet Interoperability Lab (SMIL)/streetAddress=Stensberggata 27/postalCode=0170/CN=*/',
              certType  = CertificateType.LeafCA,
              keyLength = caKeyLength, globalCRLFileName = globalCRLFileName)


# ====== Create Test Servers ================================================
subject = '/C=NO/ST=Oslo/L=Oslo/O=Simula Metropolitan Centre for Digital Engineering (SimulaMet)/OU=SimulaMet Interoperability Lab (SMIL)/streetAddress=Stensberggata 27/postalCode=0170'

certificates = { }
for certificateToCreate in certificatesToCreate:
   print(certificateToCreate)

   name = certificateToCreate['name']
   certificates[name] = Certificate(mainDirectory, name, TestLeaf,
                                    subject, certificateToCreate['subjectAltName'],
                                    certificateToCreate['type'],
                                    keyLength        = certKeyLength,
                                    revokeIfExisting = revokeIfExisting)

   if revoke:
      certificates[name].revoke()


# ====== Finally, force regeneration of the CRL to ensure it is up-to-date ==
TestLevel1.generateCRL()
