def update_crl_data(): # pylint: disable=too-many-locals """Update CRL data.""" crls = { "gdig2s1-1015.crl": { "info": "CRL in Go Daddy G2 end user certificates", "last": "2019-04-19", "name": "Go Daddy G2/user", "url": "http://crl.godaddy.com/gdig2s1-1015.crl", }, "gdroot-g2.crl": { "info": "CRL in Go Daddy G2 intermediate CA", "last": "2019-04-19", "name": "Go Daddy G2/ca", "url": "http://crl.godaddy.com/gdroot-g2.crl", }, "DSTROOTCAX3CRL.crl": { "info": "CRL in Let's Encrypt X3", "last": "2019-04-19", "name": "Let's Encrypt Authority X3/ca", "url": "http://crl.identrust.com/DSTROOTCAX3CRL.crl", }, "root-r2.crl": { "info": "CRL in GlobalSign R2", "last": "2019-04-19", "name": "GlobalSign R2/ca", "url": "http://crl.globalsign.net/root-r2.crl", }, "gsr2.crl": { "info": "CRL in Google G3 CA", "last": "2019-04-19", "name": "Google G3/ca", "url": "http://crl.pki.goog/gsr2/gsr2.crl", }, "GTSGIAG3.crl": { "info": "CRL in Google G3 end user certificates", "last": "2019-04-19", "name": "Google G3/user", "url": "http://crl.pki.goog/GTSGIAG3.crl", }, "comodo_ev_user.pem": { "info": "CRL in %s end user certificates" % certs["comodo_ev.pem"]["name"], "last": "2019-04-21", "name": "%s (user)" % cas["comodo_ev.pem"]["name"], "url": "http://crl.comodoca.com/COMODORSAExtendedValidationSecureServerCA.crl", }, "digicert_ha_intermediate.crl": { "info": "CRL in %s" % cas["digicert_ha_intermediate.pem"]["name"], "last": "2019-04-21", "name": "%s/ca" % cas["digicert_ha_intermediate.pem"]["name"], "url": "http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl", }, "digicert_ha_intermediate_user.crl": { "info": "CRL %s end user certificates" % cas["digicert_ha_intermediate.pem"]["name"], "last": "2019-04-21", "name": "%s/user" % certs["digicert_ha_intermediate.pem"]["name"], "url": "http://crl3.digicert.com/sha2-ha-server-g6.crl", }, "trustid_server_a52_ca.crl": { "info": "CRL in %s" % cas["trustid_server_a52.pem"]["name"], "last": "2019-04-21", "name": "%s/ca" % cas["trustid_server_a52.pem"]["name"], "url": "http://validation.identrust.com/crl/commercialrootca1.crl", }, "trustid_server_a52_user.crl": { "info": "CRL %s end user certificates" % cas["trustid_server_a52.pem"]["name"], "last": "2019-04-21", "name": "%s/user" % certs["trustid_server_a52.pem"]["name"], "url": "http://validation.identrust.com/crl/trustidcaa52.crl", }, } crl_dir = os.path.join(docs_base, "_files", "crl") crl_values = { # meta data "crl_info": [("CRL", "Source", "Last accessed", "Info")], "crl_issuer": [("CRL", "Issuer Name")], "crl_data": [("CRL", "Update freq.", "hash")], # extensions "crl_aki": [("CRL", "key_identifier", "cert_issuer", "cert_serial")], "crl_crlnumber": [("CRL", "number")], "crl_idp": [ ( "CRL", "full name", "relative name", "only attr certs", "only ca certs", "only user certs", "reasons", "indirect CRL", ), ], } for crl_filename in sorted(os.listdir(crl_dir), key=lambda f: crls.get(f, {}).get("name", "")): if crl_filename not in crls: common.warn("Unknown CRL: %s" % crl_filename) continue crl_name = crls[crl_filename]["name"] # set empty string as default value this_crl_values = {} for crl_key in crl_values: this_crl_values[crl_key] = [""] * (len(crl_values[crl_key][0]) - 1) with open(os.path.join(crl_dir, crl_filename), "rb") as crl_stream: crl = x509.load_der_x509_crl(crl_stream.read(), backend=default_backend()) # add info this_crl_values["crl_info"] = ( ":download:`%s </_files/crl/%s>` (`URL <%s>`__)" % (crl_filename, crl_filename, crls[crl_filename]["url"]), crls[crl_filename]["last"], crls[crl_filename]["info"], ) # add data row this_crl_values["crl_data"] = ( crl.next_update - crl.last_update, HASH_NAMES[type(crl.signature_hash_algorithm)], ) this_crl_values["crl_issuer"] = ("``%s``" % format_name(crl.issuer), ) # add extension values for ext in crl.extensions: value = ext.value if isinstance(value, x509.CRLNumber): this_crl_values["crl_crlnumber"] = (ext.value.crl_number, ) elif isinstance(value, x509.IssuingDistributionPoint): this_crl_values["crl_idp"] = ( optional( value.full_name, lambda v: "* ".join( [format_general_name(n) for n in v]), "✗"), optional(value.relative_name, format_name, "✗"), "✓" if value.only_contains_attribute_certs else "✗", "✓" if value.only_contains_ca_certs else "✗", "✓" if value.only_contains_user_certs else "✗", optional(value.only_some_reasons, lambda v: ", ".join([f.name for f in v]), "✗"), "✓" if value.indirect_crl else "✗", ) elif isinstance(value, x509.AuthorityKeyIdentifier): crl_aci = optional( value.authority_cert_issuer, lambda v: "* ".join( ["``%s``" % format_general_name(n) for n in v]), "✗", ) crl_acsn = optional(value.authority_cert_serial_number, fallback="✗") this_crl_values["crl_aki"] = (bytes_to_hex( value.key_identifier), crl_aci, crl_acsn) else: common.warn("Unknown extension: %s" % ext.oid._name) # pylint: disable=protected-access for crl_key, crl_row in this_crl_values.items(): crl_values[crl_key].append([crl_name] + list(crl_row)) # Finally, write CRL data to RST table for crl_name, crl_extensions in crl_values.items(): crl_table = tabulate(crl_extensions, headers="firstrow", tablefmt="rst") with open(os.path.join(out_base, "%s.rst" % crl_name), "w") as crl_table_stream: crl_table_stream.write(crl_table)
def update_cert_data(prefix, dirname, cert_data, name_header): """Update certificate/ca data.""" # pylint: disable=too-many-locals,too-many-branches,too-many-statements; there are many extensions cert_values = { "subject": [( name_header, "Subject", )], "issuer": [( name_header, "Issuer", )], "aia": [(name_header, "Critical", "Values")], "aki": [(name_header, "Critical", "Key identifier", "Issuer", "Serial")], "basicconstraints": [(name_header, "Critical", "CA", "Path length")], "eku": [(name_header, "Critical", "Usages")], "key_usage": [[name_header, "Critical"] + sorted(KeyUsage.CRYPTOGRAPHY_MAPPING.keys())], "ian": [(name_header, "Critical", "Names")], "ski": [(name_header, "Critical", "Digest")], "certificatepolicies": [(name_header, "Critical", "Policies")], "crldp": [(name_header, "Critical", "Names", "RDNs", "Issuer", "Reasons")], "sct": [(name_header, "Critical", "Value")], "nc": [(name_header, "Critical", "Permitted", "Excluded")], "unknown": [(name_header, "Extensions")], } exclude_empty_lines = { "unknown", } for cert_filename in sorted( os.listdir(dirname), key=lambda f: cert_data.get(f, {}).get("name", "")): if cert_filename not in cert_data: common.warn("Unknown %s: %s" % (prefix, cert_filename)) continue print("Parsing %s (%s)..." % (cert_filename, prefix)) cert_name = cert_data[cert_filename]["name"] this_cert_values = {} for cert_key in cert_values: this_cert_values[cert_key] = [""] with open(os.path.join(dirname, cert_filename), "rb") as cert_stream: cert = x509.load_pem_x509_certificate(cert_stream.read(), backend=default_backend()) this_cert_values["subject"] = ["``%s``" % format_name(cert.subject)] this_cert_values["issuer"] = ["``%s``" % format_name(cert.issuer)] for cert_ext in cert.extensions: value = cert_ext.value critical = "✓" if cert_ext.critical else "✗" if isinstance(value, x509.AuthorityInformationAccess): this_cert_values["aia"] = [ critical, "\n".join([ "* %s: %s" % ( v.access_method._name, # pylint: disable=protected-access format_general_name(v.access_location), ) for v in value ]), ] elif isinstance(value, x509.AuthorityKeyIdentifier): this_cert_values["aki"] = [ critical, bytes_to_hex(value.key_identifier), optional(value.authority_cert_issuer, format_general_name, "✗"), optional(value.authority_cert_serial_number, fallback="✗"), ] elif isinstance(value, x509.BasicConstraints): this_cert_values["basicconstraints"] = [ critical, value.ca, value.path_length if value.path_length is not None else "None", ] elif isinstance(value, x509.CRLDistributionPoints): this_cert_values["crldp"] = [] for distribution_point in value: full_name = ("* ".join([ format_general_name(name) for name in distribution_point.full_name ]) if distribution_point.full_name else "✗") issuer = ("* ".join([ format_general_name(name) for name in distribution_point.crl_issuer ]) if distribution_point.crl_issuer else "✗") reasons = (", ".join([ r.name for r in distribution_point.reasons ]) if distribution_point.reasons else "✗") relative_name = (format_name( distribution_point.relative_name) if distribution_point.relative_name else "✗") this_cert_values["crldp"].append([ critical, full_name, relative_name, issuer, reasons, ]) elif isinstance(value, x509.CertificatePolicies): policies = [] for policy in value: policy_name = policy.policy_identifier.dotted_string if policy.policy_qualifiers is None: policies.append("* %s" % policy_name) elif len(policy.policy_qualifiers) == 1: policies.append( "* %s: %s" % (policy_name, policy_as_str(policy.policy_qualifiers[0]))) else: qualifiers = "\n".join([ " * %s" % policy_as_str(p) for p in policy.policy_qualifiers ]) policies.append("* %s:\n\n%s\n" % (policy_name, qualifiers)) this_cert_values["certificatepolicies"] = [ critical, "\n".join(policies) ] elif isinstance(value, x509.ExtendedKeyUsage): this_cert_values["eku"] = [ critical, ", ".join([u._name for u in value]), # pylint: disable=protected-access ] elif isinstance(value, x509.IssuerAlternativeName): this_cert_values["ian"] = [ critical, "* ".join([format_general_name(v) for v in value]), ] elif isinstance(value, x509.KeyUsage): key_usages = [] for key in cert_values["key_usage"][0][2:]: try: key_usages.append( "✓" if getattr(value, KeyUsage. CRYPTOGRAPHY_MAPPING[key]) else "✗") except ValueError: key_usages.append("✗") this_cert_values["key_usage"] = [ critical, ] + key_usages elif isinstance(value, x509.NameConstraints): permitted = ("\n".join([ "* %s" % format_general_name(n) for n in value.permitted_subtrees ]) if value.permitted_subtrees else "✗") excluded = ("\n".join([ "* %s" % format_general_name(n) for n in value.excluded_subtrees ]) if value.excluded_subtrees else "✗") this_cert_values["nc"] = [critical, permitted, excluded] elif isinstance(value, x509.PrecertificateSignedCertificateTimestamps): this_cert_values["sct"] = [ critical, "\n".join([ "* Type: %s, version: %s" % (e.entry_type.name, e.version.name) for e in value ]), ] elif isinstance(value, x509.SubjectKeyIdentifier): this_cert_values["ski"] = [ critical, bytes_to_hex(value.digest) ] elif isinstance(value, x509.SubjectAlternativeName): continue # not interesting here else: # These are some OIDs identified by OpenSSL cli as "Netscape Cert Type" and # "Netscape Comment". They only occur in the old, discontinued StartSSL root # certificate. if cert_ext.oid.dotted_string == "2.16.840.1.113730.1.1": name = "Netscape Cert Type" elif cert_ext.oid.dotted_string == "2.16.840.1.113730.1.13": name = "Netscape Comment" else: name = cert_ext.oid._name # pylint: disable=protected-access; only way to get name ext_str = "%s (Critical: %s, OID: %s)" % ( name, cert_ext.critical, cert_ext.oid.dotted_string) this_cert_values["unknown"].append(ext_str) this_cert_values["unknown"] = [ "\n".join(["* %s" % v for v in this_cert_values["unknown"][1:]]) ] for key, row in this_cert_values.items(): if isinstance(row[0], list): cert_values[key].append([cert_name] + row[0]) for mrow in row[1:]: cert_values[key].append(["", ""] + mrow[1:]) else: cert_values[key].append([cert_name] + row) for name, values in cert_values.items(): cert_filename = os.path.join(out_base, "%s_%s.rst" % (prefix, name)) if name in exclude_empty_lines: values = [v for v in values if "".join(v[1:])] if values: table = tabulate(values, headers="firstrow", tablefmt="rst") else: table = "" with open(cert_filename, "w") as stream: stream.write(table)
this_crl_values['crl_idp'] = ( full_name, rel_name, '✓' if value.only_contains_attribute_certs else '✗', '✓' if value.only_contains_ca_certs else '✗', '✓' if value.only_contains_user_certs else '✗', reasons, '✓' if value.indirect_crl else '✗', ) elif isinstance(value, x509.AuthorityKeyIdentifier): aci = '✗' if value.authority_cert_issuer: aci = '* '.join([format_general_name(v) for v in value.authority_cert_issuer]) this_crl_values['crl_aki'] = ( bytes_to_hex(value.key_identifier), aci, value.authority_cert_serial_number if value.authority_cert_serial_number else '✗', ) else: warn('Unknown extension: %s' % ext.oid._name) for key, row in this_crl_values.items(): crl_values[key].append([crl_name] + list(row)) for name, values in crl_values.items(): filename = os.path.join(out_base, '%s.rst' % name) table = tabulate(values, headers='firstrow', tablefmt='rst') with open(filename, 'w') as stream: stream.write(table)
def _update_cert_data(prefix, cert_dir, certs, name_header): cert_values = { 'subject': [(name_header, 'Subject', )], 'issuer': [(name_header, 'Issuer', )], 'aia': [(name_header, 'Critical', 'Values')], 'aki': [(name_header, 'Critical', 'Key identifier', 'Issuer', 'Serial')], 'basicconstraints': [(name_header, 'Critical', 'CA', 'Path length')], 'eku': [(name_header, 'Critical', 'Usages')], 'key_usage': [[name_header, 'Critical', 'digital_signature', 'content_commitment', 'key_encipherment', 'data_encipherment', 'key_agreement', 'key_cert_sign', 'crl_sign', 'encipher_only', 'decipher_only', ]], 'ian': [(name_header, 'Critical', 'Names')], 'ski': [(name_header, 'Critical', 'Digest')], 'certificatepolicies': [(name_header, 'Critical', 'Policies')], 'crldp': [(name_header, 'Critical', 'Names', 'RDNs', 'Issuer', 'Reasons')], 'sct': [(name_header, 'Critical', 'Value')], 'nc': [(name_header, 'Critical', 'Permitted', 'Excluded')], 'unknown': [(name_header, 'Extensions')], } exclude_empty_lines = {'unknown', } for filename in sorted(os.listdir(cert_dir), key=lambda f: certs.get(f, {}).get('name', '')): if filename not in certs: warn('Unknown %s: %s' % (prefix, filename)) continue print('Parsing %s (%s)...' % (filename, prefix)) cert_name = certs[filename]['name'] this_cert_values = {} for key, headers in cert_values.items(): this_cert_values[key] = [''] with open(os.path.join(cert_dir, filename), 'rb') as stream: cert = x509.load_pem_x509_certificate(stream.read(), backend=default_backend()) this_cert_values['subject'] = [format_name(cert.subject)] this_cert_values['issuer'] = [format_name(cert.issuer)] for ext in cert.extensions: value = ext.value critical = '✓' if ext.critical else '✗' if isinstance(value, x509.AuthorityInformationAccess): this_cert_values['aia'] = [ critical, '\n'.join( ['* %s: %s' % (v.access_method._name, format_general_name(v.access_location)) for v in value]) ] elif isinstance(value, x509.AuthorityKeyIdentifier): aci = '✗' if value.authority_cert_issuer: aci = format_general_name(value.authority_cert_issuer) this_cert_values['aki'] = [ critical, bytes_to_hex(value.key_identifier), aci, value.authority_cert_serial_number if value.authority_cert_serial_number else '✗', ] elif isinstance(value, x509.BasicConstraints): this_cert_values['basicconstraints'] = [ critical, value.ca, value.path_length if value.path_length is not None else 'None', ] elif isinstance(value, x509.CRLDistributionPoints): this_cert_values['crldp'] = [] for dp in value: full_name = '* '.join( [format_general_name(name) for name in dp.full_name] ) if dp.full_name else '✗' issuer = '* '.join( [format_general_name(name) for name in dp.crl_issuer] ) if dp.crl_issuer else '✗' reasons = ', '.join([r.name for r in dp.reasons]) if dp.reasons else '✗' this_cert_values['crldp'].append([ critical, full_name, format_name(dp.relative_name) if dp.relative_name else '✗', issuer, reasons, ]) elif isinstance(value, x509.CertificatePolicies): policies = [] def ref_as_str(r): numbers = [str(n) for n in r.notice_numbers] return '%s: %s' % (r.organization, ', '.join(numbers)) def policy_as_str(p): if isinstance(p, six.string_types): return p elif p.explicit_text is None and p.notice_reference is None: return 'Empty UserNotice' elif p.notice_reference is None: return 'User Notice: %s' % p.explicit_text elif p.explicit_text is None: return 'User Notice: %s' % (ref_as_str(p.notice_reference)) else: return 'User Notice: %s: %s' % (ref_as_str(p.notice_reference), p.explicit_text) for policy in value: policy_name = policy.policy_identifier.dotted_string if policy.policy_qualifiers is None: policies.append('* %s' % policy_name) elif len(policy.policy_qualifiers) == 1: policies.append('* %s: %s' % ( policy_name, policy_as_str(policy.policy_qualifiers[0]) )) else: qualifiers = '\n'.join( [' * %s' % policy_as_str(p) for p in policy.policy_qualifiers] ) policies.append('* %s:\n\n%s\n' % (policy_name, qualifiers)) this_cert_values['certificatepolicies'] = [critical, '\n'.join(policies)] elif isinstance(value, x509.ExtendedKeyUsage): this_cert_values['eku'] = [ critical, ', '.join([u._name for u in value]), ] elif isinstance(value, x509.IssuerAlternativeName): this_cert_values['ian'] = [ critical, '* '.join([format_general_name(v) for v in value]), ] elif isinstance(value, x509.KeyUsage): key_usages = [] for key in cert_values['key_usage'][0][2:]: try: key_usages.append('✓' if getattr(value, key) else '✗') except ValueError: key_usages.append('✗') this_cert_values['key_usage'] = [ critical, ] + key_usages elif isinstance(value, x509.NameConstraints): permitted = '\n'.join( ['* %s' % format_general_name(n) for n in value.permitted_subtrees] ) if value.permitted_subtrees else '✗' excluded = '\n'.join( ['* %s' % format_general_name(n) for n in value.excluded_subtrees] ) if value.excluded_subtrees else '✗' this_cert_values['nc'] = [critical, permitted, excluded] elif isinstance(value, x509.PrecertificateSignedCertificateTimestamps): this_cert_values['sct'] = [ critical, '\n'.join(['* Type: %s, version: %s' % (e.entry_type.name, e.version.name) for e in value]) ] elif isinstance(value, x509.SubjectKeyIdentifier): this_cert_values['ski'] = [critical, bytes_to_hex(value.digest)] elif isinstance(value, x509.SubjectAlternativeName): continue # not interesting here else: # These are some OIDs identified by OpenSSL cli as "Netscape Cert Type" and # "Netscape Comment". They only occur in the old, discontinued StartSSL root # certificate. if ext.oid.dotted_string == '2.16.840.1.113730.1.1': name = 'Netscape Cert Type' elif ext.oid.dotted_string == '2.16.840.1.113730.1.13': name = "Netscape Comment" else: name = ext.oid._name ext_str = '%s (Critical: %s, OID: %s)' % (name, ext.critical, ext.oid.dotted_string) this_cert_values['unknown'].append(ext_str) this_cert_values['unknown'] = ['\n'.join(['* %s' % v for v in this_cert_values['unknown'][1:]])] for key, row in this_cert_values.items(): if isinstance(row[0], list): cert_values[key].append([cert_name] + row[0]) for mrow in row[1:]: cert_values[key].append(['', ''] + mrow[1:]) else: cert_values[key].append([cert_name] + row) for name, values in cert_values.items(): filename = os.path.join(out_base, '%s_%s.rst' % (prefix, name)) if name in exclude_empty_lines: values = [v for v in values if ''.join(v[1:])] if values: table = tabulate(values, headers='firstrow', tablefmt='rst') else: table = '' with open(filename, 'w') as stream: stream.write(table)
def update_crl_data(): # pylint: disable=too-many-locals """Update CRL data.""" crls = { 'gdig2s1-1015.crl': { 'info': 'CRL in Go Daddy G2 end user certificates', 'last': '2019-04-19', 'name': 'Go Daddy G2/user', 'url': 'http://crl.godaddy.com/gdig2s1-1015.crl', }, 'gdroot-g2.crl': { 'info': 'CRL in Go Daddy G2 intermediate CA', 'last': '2019-04-19', 'name': 'Go Daddy G2/ca', 'url': 'http://crl.godaddy.com/gdroot-g2.crl', }, 'DSTROOTCAX3CRL.crl': { 'info': 'CRL in Let\'s Encrypt X3', 'last': '2019-04-19', 'name': "Let's Encrypt Authority X3/ca", 'url': 'http://crl.identrust.com/DSTROOTCAX3CRL.crl', }, 'root-r2.crl': { 'info': 'CRL in GlobalSign R2', 'last': '2019-04-19', 'name': 'GlobalSign R2/ca', 'url': 'http://crl.globalsign.net/root-r2.crl', }, 'gsr2.crl': { 'info': 'CRL in Google G3 CA', 'last': '2019-04-19', 'name': 'Google G3/ca', 'url': 'http://crl.pki.goog/gsr2/gsr2.crl', }, 'GTSGIAG3.crl': { 'info': 'CRL in Google G3 end user certificates', 'last': '2019-04-19', 'name': 'Google G3/user', 'url': 'http://crl.pki.goog/GTSGIAG3.crl', }, 'comodo_ev_user.pem': { 'info': 'CRL in %s end user certificates' % certs['comodo_ev.pem']['name'], 'last': '2019-04-21', 'name': '%s/user' % cas['comodo_ev.pem']['name'], 'url': 'http://crl.comodoca.com/COMODORSAExtendedValidationSecureServerCA.crl', }, 'digicert_ha_intermediate.crl': { 'info': 'CRL in %s' % cas['digicert_ha_intermediate.pem']['name'], 'last': '2019-04-21', 'name': '%s/ca' % cas['digicert_ha_intermediate.pem']['name'], 'url': 'http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl', }, 'digicert_ha_intermediate_user.crl': { 'info': 'CRL %s end user certificates' % cas['digicert_ha_intermediate.pem']['name'], 'last': '2019-04-21', 'name': '%s/user' % certs['digicert_ha_intermediate.pem']['name'], 'url': 'http://crl3.digicert.com/sha2-ha-server-g6.crl', }, 'trustid_server_a52_ca.crl': { 'info': 'CRL in %s' % cas['trustid_server_a52.pem']['name'], 'last': '2019-04-21', 'name': '%s/ca' % cas['trustid_server_a52.pem']['name'], 'url': 'http://validation.identrust.com/crl/commercialrootca1.crl', }, 'trustid_server_a52_user.crl': { 'info': 'CRL %s end user certificates' % cas['trustid_server_a52.pem']['name'], 'last': '2019-04-21', 'name': '%s/user' % certs['trustid_server_a52.pem']['name'], 'url': 'http://validation.identrust.com/crl/trustidcaa52.crl', }, } crl_dir = os.path.join(docs_base, '_files', 'crl') crl_values = { # meta data 'crl_info': [('CRL', 'Source', 'Last accessed', 'Info')], 'crl_issuer': [('CRL', 'Issuer Name')], 'crl_data': [('CRL', 'Update freq.', 'hash')], # extensions 'crl_aki': [('CRL', 'key_identifier', 'cert_issuer', 'cert_serial')], 'crl_crlnumber': [('CRL', 'number')], 'crl_idp': [ ( 'CRL', 'full name', 'relative name', 'only attr certs', 'only ca certs', 'only user certs', 'reasons', 'indirect CRL', ), ] } for crl_filename in sorted(os.listdir(crl_dir), key=lambda f: crls.get(f, {}).get('name', '')): if crl_filename not in crls: common.warn('Unknown CRL: %s' % crl_filename) continue crl_name = crls[crl_filename]['name'] # set empty string as default value this_crl_values = {} for crl_key in crl_values: this_crl_values[crl_key] = [''] * (len(crl_values[crl_key][0]) - 1) with open(os.path.join(crl_dir, crl_filename), 'rb') as crl_stream: crl = x509.load_der_x509_crl(crl_stream.read(), backend=default_backend()) # add info this_crl_values['crl_info'] = ( ':download:`%s </_files/crl/%s>` (`URL <%s>`__)' % (crl_filename, crl_filename, crls[crl_filename]['url']), crls[crl_filename]['last'], crls[crl_filename]['info'], ) # add data row this_crl_values['crl_data'] = ( crl.next_update - crl.last_update, crl.signature_hash_algorithm.name, ) this_crl_values['crl_issuer'] = (format_name(crl.issuer), ) # add extension values for ext in crl.extensions: value = ext.value if isinstance(value, x509.CRLNumber): this_crl_values['crl_crlnumber'] = (ext.value.crl_number, ) elif isinstance(value, x509.IssuingDistributionPoint): this_crl_values['crl_idp'] = ( optional( value.full_name, lambda v: '* '.join( [format_general_name(n) for n in v]), '✗'), optional(value.relative_name, format_name, '✗'), '✓' if value.only_contains_attribute_certs else '✗', '✓' if value.only_contains_ca_certs else '✗', '✓' if value.only_contains_user_certs else '✗', optional(value.only_some_reasons, lambda v: ', '.join([f.name for f in v]), '✗'), '✓' if value.indirect_crl else '✗', ) elif isinstance(value, x509.AuthorityKeyIdentifier): crl_aci = optional( value.authority_cert_issuer, lambda v: '* '.join([format_general_name(n) for n in v]), '✗') crl_acsn = optional(value.authority_cert_serial_number, fallback='✗') this_crl_values['crl_aki'] = (bytes_to_hex( value.key_identifier), crl_aci, crl_acsn) else: common.warn('Unknown extension: %s' % ext.oid._name) # pylint: disable=protected-access for crl_key, crl_row in this_crl_values.items(): crl_values[crl_key].append([crl_name] + list(crl_row)) # Finally, write CRL data to RST table for crl_name, crl_extensions in crl_values.items(): crl_table = tabulate(crl_extensions, headers='firstrow', tablefmt='rst') with open(os.path.join(out_base, '%s.rst' % crl_name), 'w') as crl_table_stream: crl_table_stream.write(crl_table)