SSLSocket.getpeercert returns none if cert isn't valid
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 77.2k
- Fork
- 35.9k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
Bug report
Bug description:
It's possible I'm misunderstanding, but it seems the documentation around SSLSocket.getpeercert is incorrect and/or the function is bugged. This was run on Fedora 40 with python 3.12.5. I'm trying to bypass DNS and pull the SSL cert straight from an IP for a specific set of Hosts.
the docs I'm referencing: https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert
Site and HostIP are variables representing a site URL and a Apache server's direct IP address. This is inside a function call.
the code:
#empty cert info dict
SiteCertInfo = {}
#create SSL context and socket
#this overrides "DNS" so we can pull the SSL cert as it is on the server
sslContext = ssl.create_default_context()
sslSock = socket.socket()
sslConn = sslContext.wrap_socket(sslSock, server_hostname=Site)
#try the connection
try:
sslConn.connect((HostIp, 443))
#ssl cert can't be verified / doesn't match
except ssl.SSLCertVerificationError as ex:
#show error reasons
print(Site + " site SSL did not verify. reason: " + ex.verify_message, file=sys.stderr)
#continue
pass
#pull the cert from the connection
sslCert = sslConn.getpeercert()
The error:
sslCert = sslConn.getpeercert()
^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.12/ssl.py", line 1129, in getpeercert
return self._sslobj.getpeercert(binary_form)
^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'getpeercert'
The issue:
The documentation states "for a client SSL socket, the server will always provide a certificate, regardless of whether validation was required;" I'm reading that as my python "client" connecting to the remote server should always get a cert even if it fails validation.
However, if the certificate is expired I'm catching the error and continuing on via the pass call. The sslConn.getpeercert() call fails as sslConn is None. If I don't catch the error then it just fails as normal.
If I try and by-pass validation by doing:
sslContext = ssl.SSLContext(protocol = ssl.PROTOCOL_TLS_CLIENT)
sslContext.check_hostname = False
sslContext.verify_mode = ssl.CERT_NONE
sslContext.set_default_verify_paths()
This just fails and pulls a "empty" dict for sslCert. If I set verify_mode back to CERT_REQUIRED I'm back to square one.
So, there doesn't seem to be a way to "catch" the validation error, but still continue to load the cert if the cert is expired or to disable validation via CERT_NONE and still pull the cert data and manually "validate" it.
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với hành vi được ghi trong tài liệu của ssl.SSLSocket.getpeercert và các thiết lập xác minh của SSLContext, sau đó tái hiện luồng kết nối được báo cáo bằng chứng chỉ đã hết hạn và CERT_NONE. So sánh trạng thái socket sau SSLCertVerificationError với kết quả của getpeercert(binary_form=True). Hoàn tất khi xác định được hành vi này là lỗi triển khai hay vấn đề tài liệu, đồng thời thêm regression test tương ứng hoặc làm rõ tài liệu.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- networking, security
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 35/100