使用Python获取证书颁发者名称为何顺序反转?
我使用Python的cryptography.x509模块读取证书时,遇到了颁发者名称顺序反转的问题:正确的颁发者名称应为CN=PEZEINVOICESCA2-CA,DC=extgazt,DC=gov,DC=local,但通过代码获取到的却是DC=local,DC=gov,DC=extgazt,CN=PEZEINVOICESCA2-CA。
我原本使用的代码如下:
import cryptography.x509 your_Certificate = open("cert.txt","rb") Certificate = your_Certificate.read().decode() your_Certificate.close() the_certificate = cryptography.x509.load_pem_x509_certificate("-----BEGIN CERTIFICATE----- {} -----END CERTIFICATE-----".format(Certificate).encode()) issuer_name = (str(the_certificate.issuer).split("(")[-1].split(")")[0]) print(issuer_name)
我的证书内容为:
MIIFGTCCBMCgAwIBAgITbQAABwotIOM7hEGkOwAAAAAHCjAKBggqhkjOPQQDAjBiMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNnb3YxFzAVBgoJkiaJk/IsZAEZFgdleHRnYXp0MRswGQYDVQQDExJQRVpFSU5WT0lDRVNDQTItQ0EwHhcNMjMwNTIxMDkxMjE3WhcNMjMwODA4MTIyNjQ2WjBZMQswCQYDVQQGEwJTQTEhMB8GA1UEChMYTW9oYW1tZWQgYWxtYWxraSBjb21wYW55MREwDwYDVQQLEwhtb2hhbW1lZDEUMBIGA1UEAxMLZGV2aWNlIG11c2EwVjAQBgcqhkjOPQIBBgUrgQQACgNCAAStYLyBf9nWo3vWtzUkM2itMt/8euVz4Kao8fqz8SqUKl46RzqyhUUjR4gij3HvA6gBbHT1ai2O5JaAeaj1/4G3o4IDXzCCA1swJwYJKwYBBAGCNxUKBBowGDAKBggrBgEFBQcDAjAKBggrBgEFBQcDAzA8BgkrBgEEAYI3FQcELzAtBiUrBgEEAYI3FQiBhqgdhND7EobtnSSHzvsZ08BVZoGc2C2D5cVdAgFkAgETMIHNBggrBgEFBQcBAQSBwDCBvTCBugYIKwYBBQUHMAKGga1sZGFwOi8vL0NOPVBFWkVJTlZPSUNFU0NBMi1DQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1leHRnYXp0LERDPWdvdixEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTAdBgNVHQ4EFgQUDQdY1rouelOIOWWyJ8ByNGfyKeQwDgYDVR0PAQH/BAQDAgeAMIHOBgNVHREEgcYwgcOkgcAwgb0xVTBTBgNVBAQMTDEta2FyYWZldGFfcHJncmFtfDItdGhlX2RldmljZV9uYW1lX2lzX2RldmljZSBtdXNhfDMtdGhlX2RldmljZV9udW1iZXJfaXNfNTAxHzAdBgoJkiaJk/IsZAEBDA8zMTExOTAyOTM3MDAwMDMxDTALBgNVBAwMBDExMDAxDjAMBgNVBBoMBWphemFuMSQwIgYDVQQPDBt0ZWNobm9sb2d5IGFuZCBjb25zdWx0YXRpb24wgeEGA1UdHwSB2TCB1jCB06CB0KCBzYaBymxkYXA6Ly8vQ049UEVaRUlOVk9JQ0VTQ0EyLUNBLENOPVBFWkVpbnZvaWNlc2NhMixDTj1DRFAsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1leHRnYXp0LERDPWdvdixEQz1sb2NhbD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwHwYDVR0jBBgwFoAUh6XbAr13zUdvaQF7eC0a9e7HwFEwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMDMAoGCCqGSM49BAMCA0cAMEQCIHu3KKPhtrWF86EyD1p5GZ0fDzrRIrAVQpO0S4HYZEyfAiArNL/YVPyE+QdNH5AF4CGqIA+wpBYe9vVngMdGlvOwJA==
解决方案
问题出在直接将issuer对象转成字符串切割的方式上。X.509证书的可分辨名称(DN)在ASN.1编码中是从最底层属性(如DC=local)到最上层属性(如CN=XXX)存储的,但我们习惯的显示顺序是反过来的。
改用遍历属性并按正确顺序拼接的方式:
import cryptography.x509 # 更安全的文件读取方式 with open("cert.txt", "rb") as f: cert_content = f.read().decode() # 构造PEM格式证书并加载 pem_cert = f"-----BEGIN CERTIFICATE-----\n{cert_content}\n-----END CERTIFICATE-----".encode() the_certificate = cryptography.x509.load_pem_x509_certificate(pem_cert) # 按反向顺序遍历相对可分辨名称,拼接成符合习惯的格式 issuer_parts = [] # rdns是相对可分辨名称列表,反转后得到从CN到DC的顺序 for rdn in reversed(the_certificate.issuer.rdns): for attr in rdn: # 获取属性名称的友好标识(如CN、DC) oid_name = attr.oid._name value = attr.value issuer_parts.append(f"{oid_name}={value}") issuer_name = ", ".join(issuer_parts) print(issuer_name)
这段代码会直接输出正确顺序的颁发者名称:CN=PEZEINVOICESCA2-CA, DC=extgazt, DC=gov, DC=local。
说明
the_certificate.issuer.rdns返回证书颁发者的相对可分辨名称(RDN)列表,每个RDN包含一个或多个属性。- 反转列表后,就能得到我们习惯的从最上层(CN)到最底层(DC=local)的显示顺序。
- 通过
attr.oid._name可以获取属性的友好标识符,避免使用OID的原始数字标识。
内容的提问来源于stack exchange,提问作者Mohammed almalki

