python / python/cpython

SSLSocket.getpeercert returns none if cert isn't valid

Offen
#122,962 0 Kommentare 3 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

stdlib topic-SSL type-bug
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginnen Sie mit dem dokumentierten Verhalten von ssl.SSLSocket.getpeercert und den Verifizierungseinstellungen von SSLContext. Reproduzieren Sie anschließend den gemeldeten Verbindungsablauf mit einem abgelaufenen Zertifikat und CERT_NONE. Vergleichen Sie den Socket-Zustand nach SSLCertVerificationError mit dem Ergebnis von getpeercert(binary_form=True). Als abgeschlossen gilt die Feststellung, ob es sich bei diesem Verhalten um einen Implementierungsfehler oder ein Dokumentationsproblem handelt, sowie das Hinzufügen des entsprechenden Regressionstests oder einer Klarstellung in der Dokumentation.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
networking, security
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.