File indexing completed on 2024-11-24 04:44:41

0001 #!/usr/bin/env python3
0002 # SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
0003 # SPDX-License-Identifier: LGPL-2.0-or-later
0004 
0005 import argparse
0006 import os
0007 import subprocess
0008 import pyasn1
0009 import shutil
0010 
0011 from pyasn1.codec.der.decoder import decode
0012 from pyasn1.codec.der.encoder import encode
0013 
0014 derFileNames = []
0015 
0016 def writeToFile(fileName, content):
0017     f = open(fileName, 'wb')
0018     f.write(content)
0019     f.close();
0020 
0021 def runOpenSsl(args, data = None):
0022     proc = subprocess.Popen(f"openssl {args}", shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
0023     if data != None:
0024         proc.stdin.write(data)
0025         proc.stdin.close()
0026     return proc.stdout.read()
0027 
0028 def removeExistingCerts():
0029     for certFile in os.listdir(arguments.output):
0030         path = os.path.join(arguments.output, certFile)
0031         if certFile.endswith('.der'):
0032             os.remove(path)
0033         elif os.path.isdir(path):
0034             shutil.rmtree(path)
0035 
0036 def unpackMlFile(mlFileName):
0037     print (f"processing {mlFileName}")
0038     mlPemFile = runOpenSsl(f"cms -inform der -noverify -verify -in {mlFileName}")
0039     pems, _ = pyasn1.codec.der.decoder.decode(mlPemFile)
0040     keyData = {}
0041     i = 0
0042     while True:
0043         pemObj = pems.getComponentByPosition(1).getComponentByPosition(i, instantiate=False, default=None)
0044         if pemObj == None:
0045             break;
0046         pemData = pyasn1.codec.der.encoder.encode(pemObj)
0047         keyId = runOpenSsl('x509 -inform der -text -noout | grep -A1 "Subject Key Identifier" | tail -n 1', pemData).strip().decode().replace(':', '').lower()
0048         serial = runOpenSsl('x509 -inform der -serial -noout', pemData).strip().decode().replace('serial=', '').lower()
0049         if not keyId in keyData:
0050             keyData[keyId] = []
0051         keyData[keyId].append((pemData, serial))
0052         i += 1
0053 
0054     # write certificates
0055     for keyId in keyData:
0056         if len(keyData[keyId]) == 1:
0057             writeToFile(os.path.join(arguments.output, f"{keyId}.der"), keyData[keyId][0][0])
0058             derFileNames.append(f"{keyId}.der")
0059         else:
0060             os.mkdir(os.path.join(arguments.output, keyId))
0061             for (cert,serial) in keyData[keyId]:
0062                 writeToFile(os.path.join(arguments.output, keyId, f"{serial}.der"), cert)
0063                 derFileNames.append(f"{keyId}/{serial}.der")
0064 
0065 def writeQrcFile():
0066     derFileNames.sort()
0067     qrcFile = open(os.path.join(arguments.output, 'icao-csca-certs.qrc'), 'w')
0068     qrcFile.write("""<!--
0069     SPDX-FileCopyrightText: none
0070     SPDX-License-Identifier: CC0-1.0
0071 -->
0072 <RCC>
0073   <qresource prefix="/org.kde.khealthcertificate/icao/certs">
0074 """)
0075     for derFileName in derFileNames:
0076         qrcFile.write(f"    <file>{derFileName}</file>\n")
0077     qrcFile.write("  </qresource>\n</RCC>")
0078     qrcFile.close()
0079 
0080 
0081 parser = argparse.ArgumentParser(description='Download and unpack ICAO CSCA master lists.')
0082 parser.add_argument('--output', type=str, required=True, help='Path to which the output should be written to')
0083 arguments = parser.parse_args()
0084 
0085 removeExistingCerts()
0086 
0087 #unpackMlFile('ICAO_health_ml_27May2022.ml')
0088 #unpackMlFile('ICAO_ml_June_2022.ml')
0089 
0090 # from https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/ElekAusweise/CSCA/GermanMasterList.zip
0091 unpackMlFile('20220623_DEMasterList.ml')
0092 
0093 writeQrcFile()