2017-08-03 104 views
2

我試圖獲得證書頒發者信息(通用名稱),但鏈接中的代碼不適用於某些URL。Python使用ssl.getpeercert()從URL獲取通用名稱

How can i get Certificate issuer information in python?

import ssl, socket 

hostname = 'google.com' 
ctx = ssl.create_default_context() 
s = ctx.wrap_socket(socket.socket(), server_hostname=hostname) 
s.connect((hostname, 443)) 
cert = s.getpeercert() 

subject = dict(x[0] for x in cert['subject']) 
issued_to = subject['commonName'] 

>>> issued_to 
u'*.google.com' 

例如,我試圖主機名 「cds.ca」,它說

ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661) 

,但我仍然可以使用Internet Explorer(* .cds.ca獲得通用名)

所以我認爲我應該使用自己的證書(.cer)而不是使用getpeercert(),那麼應該如何更改該行?

或者,有沒有其他方法可以用我自己的證書文件來實現CN?

+0

你是問如何確保該證書驗證,以獲得成功CN或即使證書驗證失敗,如何獲得CN? –

+0

兩者都可以。我試了後者(查找了許多關於忽略證書驗證的問題),但是我失敗了:( – Sean

+0

從網站獲取CN(與Internet Explorer顯示的相同)是我想要的。 – Sean

回答

1

如果您只想獲取CN或其他證書詳細信息,無論證書驗證是否成功,您必須禁用驗證。不幸的是,一個簡單的sock.getpeercert()將通過設計僅在證書驗證被禁用時才返回空字典。這就是爲什麼人們必須使用sock.getpeercert(True)拿到證書的二進制表示和CN使用OpenSSL.crypto從中提取:

import socket 
import ssl 
import OpenSSL.crypto as crypto 

dst = ('cds.ca',443) 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect(dst) 

# upgrade the socket to SSL without checking the certificate 
# !!!! don't transfer any sensitive data over this socket !!!! 
ctx = ssl.create_default_context() 
ctx.check_hostname = False 
ctx.verify_mode = ssl.CERT_NONE 
s = ctx.wrap_socket(s, server_hostname=dst[0]) 

# get certificate 
cert_bin = s.getpeercert(True) 
x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,cert_bin) 
print("CN=" + x509.get_subject().CN) 
+0

它的工作原理非常好。 – Sean