@@ -398,6 +398,43 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
398398 return context
399399
400400
401+ def _create_stdlib_context (protocol = PROTOCOL_SSLv23 , * , cert_reqs = None ,
402+ purpose = Purpose .SERVER_AUTH ,
403+ certfile = None , keyfile = None ,
404+ cafile = None , capath = None , cadata = None ):
405+ """Create a SSLContext object for Python stdlib modules
406+
407+ All Python stdlib modules shall use this function to create SSLContext
408+ objects in order to keep common settings in one place. The configuration
409+ is less restrict than create_default_context()'s to increase backward
410+ compatibility.
411+ """
412+ if not isinstance (purpose , _ASN1Object ):
413+ raise TypeError (purpose )
414+
415+ context = SSLContext (protocol )
416+ # SSLv2 considered harmful.
417+ context .options |= OP_NO_SSLv2
418+
419+ if cert_reqs is not None :
420+ context .verify_mode = cert_reqs
421+
422+ if keyfile and not certfile :
423+ raise ValueError ("certfile must be specified" )
424+ if certfile or keyfile :
425+ context .load_cert_chain (certfile , keyfile )
426+
427+ # load CA root certs
428+ if cafile or capath or cadata :
429+ context .load_verify_locations (cafile , capath , cadata )
430+ elif context .verify_mode != CERT_NONE :
431+ # no explicit cafile, capath or cadata but the verify mode is
432+ # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system
433+ # root CA certificates for the given purpose. This may fail silently.
434+ context .load_default_certs (purpose )
435+
436+ return context
437+
401438class SSLSocket (socket ):
402439 """This class implements a subtype of socket.socket that wraps
403440 the underlying OS socket in an SSL context when necessary, and
@@ -829,15 +866,16 @@ def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None):
829866 If 'ssl_version' is specified, use it in the connection attempt."""
830867
831868 host , port = addr
832- if ( ca_certs is not None ) :
869+ if ca_certs is not None :
833870 cert_reqs = CERT_REQUIRED
834871 else :
835872 cert_reqs = CERT_NONE
836- s = create_connection (addr )
837- s = wrap_socket (s , ssl_version = ssl_version ,
838- cert_reqs = cert_reqs , ca_certs = ca_certs )
839- dercert = s .getpeercert (True )
840- s .close ()
873+ context = _create_stdlib_context (ssl_version ,
874+ cert_reqs = cert_reqs ,
875+ cafile = ca_certs )
876+ with create_connection (addr ) as sock :
877+ with context .wrap_socket (sock ) as sslsock :
878+ dercert = sslsock .getpeercert (True )
841879 return DER_cert_to_PEM_cert (dercert )
842880
843881def get_protocol_name (protocol_code ):
0 commit comments