From b89105fa67eb613f80164bb774e6d5baedad17d4 Mon Sep 17 00:00:00 2001 From: Ruben van Staveren Date: Wed, 27 Jul 2022 13:10:08 +0000 Subject: [PATCH] Feature/01 python39 regression --- .gitignore | 1 + sort_certificate.py | 53 +++++++++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 45d62d8..94d5d96 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.sw? +__pycache__ diff --git a/sort_certificate.py b/sort_certificate.py index db26b60..5115007 100755 --- a/sort_certificate.py +++ b/sort_certificate.py @@ -176,7 +176,15 @@ def find_root(x509_objects, root_issuers): ''' Find a suitable anchor by finding the intermediate that was signed by root ''' - root_cert = root_issuers[str(x509_objects[-1].get_issuer())] + root_cert = None + for x509_object in reversed(x509_objects): + if str(x509_object.get_issuer()) in root_issuers: + root_cert = root_issuers[str(x509_object.get_issuer())] + break + if not root_cert: + raise CertificateComponentException('Unable to find a suitable ' + 'trusted root certificate ' + 'for bundle') logging.debug('Retrieved root certificate %s', root_cert.get_subject()) return root_cert @@ -187,17 +195,21 @@ def find_intermediate_root(x509_objects, root_issuers): ''' # Some intermediates have the *same* subject as some root certificates. - # blacklist them - # XXX better use pubkey/hash for that, but can't find the appropriate - # interface to that at the moment + # blacklist them if their issuer and subject name is present in the root + # bundle excluded_issuers = [str(x.get_subject()) for x in x509_objects - if x.get_subject() != x.get_issuer()] + if x.get_subject() != x.get_issuer() + and str(x.get_issuer()) in root_issuers + and str(x.get_subject()) in root_issuers] logging.debug('Known root issuers\n\t%s', '\n\t'.join(root_issuers)) logging.debug('Excluding issuers because of potential intermediates\n\t%s', '\n\t'.join(excluded_issuers)) - logging.debug('issuers seen in data\n\t%s', - '\n\t'.join([str(x.get_issuer()) for x in x509_objects])) + logging.debug('Certificates seen in data\n\t%s', + '\n\t'.join([f'Subject: {x.get_subject()},' + f' Issuer: {x.get_issuer()}' + for x in x509_objects])) + return [x for x in x509_objects if str(x.get_issuer()) in root_issuers and str(x.get_issuer()) not in excluded_issuers] @@ -214,15 +226,14 @@ def order_x509(x509_objects, root_issuers): logging.warning('Found self signed (root) certificate %s in input', str(root_crt.get_subject())) # Double check if our self signed root certificate is not also present - # as an intermediate: - # - It is probably invalid input, and doesn't make sense - # - It confuses the ordering process + # as an cross signed intermediate: + # - It might confuse the ordering process if next((x for x in x509_objects if x.get_subject() != x.get_issuer() and x.get_subject() == root_crt.get_subject()), None): - raise CertificateComponentException('Both present as intermediate ' - 'and root certificate: %s' % - str(root_crt.get_subject())) + logging.warning('Both present as intermediate ' + 'and root certificate: %s' % + str(root_crt.get_subject())) else: # Get intermediate cert signed by any root from bundle as anchor, and # make that our root @@ -248,11 +259,24 @@ def order_x509(x509_objects, root_issuers): while x509_objects: sibling = [x for x in x509_objects if x.get_issuer() == bundle[0].get_subject()] + parent = [x for x in x509_objects + if x.get_subject() == bundle[-1].get_issuer()] if sibling and len(sibling) == 1: # insert sibling at beginning of list bundle.insert(0, x509_objects.pop(x509_objects.index(sibling[0]))) + elif parent and len(parent) == 1: + # Try to place a (cross signed) intermediate at the end if it matches + bundle.append(x509_objects.pop(x509_objects.index(parent[0]))) else: # Lets complain + logging.error('Certificates remaining data\n\t%s', + '\n\t'.join([f'Subject: {x.get_subject()},' + f' Issuer: {x.get_issuer()}' + for x in x509_objects])) + logging.error('Certificates placed in bundle \n\t%s', + '\n\t'.join([f'Subject: {x.get_subject()},' + f' Issuer: {x.get_issuer()}' + for x in bundle])) raise CertificateComponentException('Non matching certificates in ' 'input:' ' No sibling found for %s' @@ -294,7 +318,8 @@ def load_root_issuers(): continue root_issuers = {str(root_cert.get_subject()): root_cert - for root_cert in root_certs} + for root_cert in root_certs + if not root_cert.has_expired()} return root_issuers