_ssl3.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. # Wrapper module for _ssl. Written by Bill Janssen.
  2. # Ported to gevent by Denis Bilenko.
  3. """SSL wrapper for socket objects on Python 3.
  4. For the documentation, refer to :mod:`ssl` module manual.
  5. This module implements cooperative SSL socket wrappers.
  6. """
  7. # Our import magic sadly makes this warning useless
  8. # pylint: disable=undefined-variable
  9. from __future__ import absolute_import
  10. import ssl as __ssl__
  11. _ssl = __ssl__._ssl # pylint:disable=no-member
  12. import errno
  13. from gevent.socket import socket, timeout_default
  14. from gevent.socket import error as socket_error
  15. from gevent.socket import timeout as _socket_timeout
  16. from gevent._util import copy_globals
  17. from weakref import ref as _wref
  18. __implements__ = [
  19. 'SSLContext',
  20. 'SSLSocket',
  21. 'wrap_socket',
  22. 'get_server_certificate',
  23. ]
  24. # Import all symbols from Python's ssl.py, except those that we are implementing
  25. # and "private" symbols.
  26. __imports__ = copy_globals(__ssl__, globals(),
  27. # SSLSocket *must* subclass gevent.socket.socket; see issue 597
  28. names_to_ignore=__implements__ + ['socket'],
  29. dunder_names_to_keep=())
  30. __all__ = __implements__ + __imports__
  31. if 'namedtuple' in __all__:
  32. __all__.remove('namedtuple')
  33. orig_SSLContext = __ssl__.SSLContext # pylint:disable=no-member
  34. class SSLContext(orig_SSLContext):
  35. def wrap_socket(self, sock, server_side=False,
  36. do_handshake_on_connect=True,
  37. suppress_ragged_eofs=True,
  38. server_hostname=None,
  39. session=None):
  40. # pylint:disable=arguments-differ
  41. # (3.6 adds session)
  42. # Sadly, using *args and **kwargs doesn't work
  43. return SSLSocket(sock=sock, server_side=server_side,
  44. do_handshake_on_connect=do_handshake_on_connect,
  45. suppress_ragged_eofs=suppress_ragged_eofs,
  46. server_hostname=server_hostname,
  47. _context=self,
  48. _session=session)
  49. if not hasattr(orig_SSLContext, 'check_hostname'):
  50. # Python 3.3 lacks this
  51. check_hostname = False
  52. if hasattr(orig_SSLContext.options, 'setter'):
  53. # In 3.6, these became properties. They want to access the
  54. # property __set__ method in the superclass, and they do so by using
  55. # super(SSLContext, SSLContext). But we rebind SSLContext when we monkey
  56. # patch, which causes infinite recursion.
  57. # https://github.com/python/cpython/commit/328067c468f82e4ec1b5c510a4e84509e010f296
  58. # pylint:disable=no-member
  59. @orig_SSLContext.options.setter
  60. def options(self, value):
  61. super(orig_SSLContext, orig_SSLContext).options.__set__(self, value)
  62. @orig_SSLContext.verify_flags.setter
  63. def verify_flags(self, value):
  64. super(orig_SSLContext, orig_SSLContext).verify_flags.__set__(self, value)
  65. @orig_SSLContext.verify_mode.setter
  66. def verify_mode(self, value):
  67. super(orig_SSLContext, orig_SSLContext).verify_mode.__set__(self, value)
  68. class _contextawaresock(socket._gevent_sock_class): # Python 2: pylint:disable=slots-on-old-class
  69. # We have to pass the raw stdlib socket to SSLContext.wrap_socket.
  70. # That method in turn can pass that object on to things like SNI callbacks.
  71. # It wouldn't have access to any of the attributes on the SSLSocket, like
  72. # context, that it's supposed to (see test_ssl.test_sni_callback). Our
  73. # solution is to keep a weak reference to the SSLSocket on the raw
  74. # socket and delegate.
  75. # We keep it in a slot to avoid having the ability to set any attributes
  76. # we're not prepared for (because we don't know what to delegate.)
  77. __slots__ = ('_sslsock',)
  78. @property
  79. def context(self):
  80. return self._sslsock().context
  81. @context.setter
  82. def context(self, ctx):
  83. self._sslsock().context = ctx
  84. @property
  85. def session(self):
  86. """The SSLSession for client socket."""
  87. return self._sslsock().session
  88. @session.setter
  89. def session(self, session):
  90. self._sslsock().session = session
  91. def __getattr__(self, name):
  92. try:
  93. return getattr(self._sslsock(), name)
  94. except RuntimeError:
  95. # XXX: If the attribute doesn't exist,
  96. # we infinitely recurse
  97. pass
  98. raise AttributeError(name)
  99. class SSLSocket(socket):
  100. """
  101. gevent `ssl.SSLSocket <https://docs.python.org/3/library/ssl.html#ssl-sockets>`_
  102. for Python 3.
  103. """
  104. # pylint:disable=too-many-instance-attributes,too-many-public-methods
  105. _gevent_sock_class = _contextawaresock
  106. def __init__(self, sock=None, keyfile=None, certfile=None,
  107. server_side=False, cert_reqs=CERT_NONE,
  108. ssl_version=PROTOCOL_SSLv23, ca_certs=None,
  109. do_handshake_on_connect=True,
  110. family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
  111. suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
  112. server_hostname=None,
  113. _session=None, # 3.6
  114. _context=None):
  115. # pylint:disable=too-many-locals,too-many-statements,too-many-branches
  116. if _context:
  117. self._context = _context
  118. else:
  119. if server_side and not certfile:
  120. raise ValueError("certfile must be specified for server-side "
  121. "operations")
  122. if keyfile and not certfile:
  123. raise ValueError("certfile must be specified")
  124. if certfile and not keyfile:
  125. keyfile = certfile
  126. self._context = SSLContext(ssl_version)
  127. self._context.verify_mode = cert_reqs
  128. if ca_certs:
  129. self._context.load_verify_locations(ca_certs)
  130. if certfile:
  131. self._context.load_cert_chain(certfile, keyfile)
  132. if npn_protocols:
  133. self._context.set_npn_protocols(npn_protocols)
  134. if ciphers:
  135. self._context.set_ciphers(ciphers)
  136. self.keyfile = keyfile
  137. self.certfile = certfile
  138. self.cert_reqs = cert_reqs
  139. self.ssl_version = ssl_version
  140. self.ca_certs = ca_certs
  141. self.ciphers = ciphers
  142. # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get
  143. # mixed in.
  144. if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
  145. raise NotImplementedError("only stream sockets are supported")
  146. if server_side:
  147. if server_hostname:
  148. raise ValueError("server_hostname can only be specified "
  149. "in client mode")
  150. if _session is not None:
  151. raise ValueError("session can only be specified "
  152. "in client mode")
  153. if self._context.check_hostname and not server_hostname:
  154. raise ValueError("check_hostname requires server_hostname")
  155. self._session = _session
  156. self.server_side = server_side
  157. self.server_hostname = server_hostname
  158. self.do_handshake_on_connect = do_handshake_on_connect
  159. self.suppress_ragged_eofs = suppress_ragged_eofs
  160. connected = False
  161. if sock is not None:
  162. socket.__init__(self,
  163. family=sock.family,
  164. type=sock.type,
  165. proto=sock.proto,
  166. fileno=sock.fileno())
  167. self.settimeout(sock.gettimeout())
  168. # see if it's connected
  169. try:
  170. sock.getpeername()
  171. except socket_error as e:
  172. if e.errno != errno.ENOTCONN:
  173. raise
  174. else:
  175. connected = True
  176. sock.detach()
  177. elif fileno is not None:
  178. socket.__init__(self, fileno=fileno)
  179. else:
  180. socket.__init__(self, family=family, type=type, proto=proto)
  181. self._sock._sslsock = _wref(self)
  182. self._closed = False
  183. self._sslobj = None
  184. self._connected = connected
  185. if connected:
  186. # create the SSL object
  187. try:
  188. self._sslobj = self._context._wrap_socket(self._sock, server_side,
  189. server_hostname)
  190. if _session is not None: # 3.6
  191. self._sslobj = SSLObject(self._sslobj, owner=self, session=self._session)
  192. if do_handshake_on_connect:
  193. timeout = self.gettimeout()
  194. if timeout == 0.0:
  195. # non-blocking
  196. raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
  197. self.do_handshake()
  198. except socket_error as x:
  199. self.close()
  200. raise x
  201. @property
  202. def context(self):
  203. return self._context
  204. @context.setter
  205. def context(self, ctx):
  206. self._context = ctx
  207. self._sslobj.context = ctx
  208. @property
  209. def session(self):
  210. """The SSLSession for client socket."""
  211. if self._sslobj is not None:
  212. return self._sslobj.session
  213. @session.setter
  214. def session(self, session):
  215. self._session = session
  216. if self._sslobj is not None:
  217. self._sslobj.session = session
  218. @property
  219. def session_reused(self):
  220. """Was the client session reused during handshake"""
  221. if self._sslobj is not None:
  222. return self._sslobj.session_reused
  223. def dup(self):
  224. raise NotImplementedError("Can't dup() %s instances" %
  225. self.__class__.__name__)
  226. def _checkClosed(self, msg=None):
  227. # raise an exception here if you wish to check for spurious closes
  228. pass
  229. def _check_connected(self):
  230. if not self._connected:
  231. # getpeername() will raise ENOTCONN if the socket is really
  232. # not connected; note that we can be connected even without
  233. # _connected being set, e.g. if connect() first returned
  234. # EAGAIN.
  235. self.getpeername()
  236. def read(self, len=1024, buffer=None):
  237. """Read up to LEN bytes and return them.
  238. Return zero-length string on EOF."""
  239. # pylint:disable=too-many-branches
  240. self._checkClosed()
  241. while True:
  242. if not self._sslobj:
  243. raise ValueError("Read on closed or unwrapped SSL socket.")
  244. if len == 0:
  245. return b'' if buffer is None else 0
  246. # Negative lengths are handled natively when the buffer is None
  247. # to raise a ValueError
  248. try:
  249. if buffer is not None:
  250. return self._sslobj.read(len, buffer)
  251. return self._sslobj.read(len or 1024)
  252. except SSLWantReadError:
  253. if self.timeout == 0.0:
  254. raise
  255. self._wait(self._read_event, timeout_exc=_SSLErrorReadTimeout)
  256. except SSLWantWriteError:
  257. if self.timeout == 0.0:
  258. raise
  259. # note: using _SSLErrorReadTimeout rather than _SSLErrorWriteTimeout below is intentional
  260. self._wait(self._write_event, timeout_exc=_SSLErrorReadTimeout)
  261. except SSLError as ex:
  262. if ex.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
  263. if buffer is None:
  264. return b''
  265. return 0
  266. else:
  267. raise
  268. def write(self, data):
  269. """Write DATA to the underlying SSL channel. Returns
  270. number of bytes of DATA actually transmitted."""
  271. self._checkClosed()
  272. while True:
  273. if not self._sslobj:
  274. raise ValueError("Write on closed or unwrapped SSL socket.")
  275. try:
  276. return self._sslobj.write(data)
  277. except SSLError as ex:
  278. if ex.args[0] == SSL_ERROR_WANT_READ:
  279. if self.timeout == 0.0:
  280. raise
  281. self._wait(self._read_event, timeout_exc=_SSLErrorWriteTimeout)
  282. elif ex.args[0] == SSL_ERROR_WANT_WRITE:
  283. if self.timeout == 0.0:
  284. raise
  285. self._wait(self._write_event, timeout_exc=_SSLErrorWriteTimeout)
  286. else:
  287. raise
  288. def getpeercert(self, binary_form=False):
  289. """Returns a formatted version of the data in the
  290. certificate provided by the other end of the SSL channel.
  291. Return None if no certificate was provided, {} if a
  292. certificate was provided, but not validated."""
  293. self._checkClosed()
  294. self._check_connected()
  295. try:
  296. c = self._sslobj.peer_certificate
  297. except AttributeError:
  298. # 3.6
  299. c = self._sslobj.getpeercert
  300. return c(binary_form)
  301. def selected_npn_protocol(self):
  302. self._checkClosed()
  303. if not self._sslobj or not _ssl.HAS_NPN:
  304. return None
  305. return self._sslobj.selected_npn_protocol()
  306. if hasattr(_ssl, 'HAS_ALPN'):
  307. # 3.5+
  308. def selected_alpn_protocol(self):
  309. self._checkClosed()
  310. if not self._sslobj or not _ssl.HAS_ALPN: # pylint:disable=no-member
  311. return None
  312. return self._sslobj.selected_alpn_protocol()
  313. def shared_ciphers(self):
  314. """Return a list of ciphers shared by the client during the handshake or
  315. None if this is not a valid server connection.
  316. """
  317. return self._sslobj.shared_ciphers()
  318. def version(self):
  319. """Return a string identifying the protocol version used by the
  320. current SSL channel. """
  321. if not self._sslobj:
  322. return None
  323. return self._sslobj.version()
  324. # We inherit sendfile from super(); it always uses `send`
  325. def cipher(self):
  326. self._checkClosed()
  327. if not self._sslobj:
  328. return None
  329. return self._sslobj.cipher()
  330. def compression(self):
  331. self._checkClosed()
  332. if not self._sslobj:
  333. return None
  334. return self._sslobj.compression()
  335. def send(self, data, flags=0, timeout=timeout_default):
  336. self._checkClosed()
  337. if timeout is timeout_default:
  338. timeout = self.timeout
  339. if self._sslobj:
  340. if flags != 0:
  341. raise ValueError(
  342. "non-zero flags not allowed in calls to send() on %s" %
  343. self.__class__)
  344. while True:
  345. try:
  346. return self._sslobj.write(data)
  347. except SSLWantReadError:
  348. if self.timeout == 0.0:
  349. return 0
  350. self._wait(self._read_event)
  351. except SSLWantWriteError:
  352. if self.timeout == 0.0:
  353. return 0
  354. self._wait(self._write_event)
  355. else:
  356. return socket.send(self, data, flags, timeout)
  357. def sendto(self, data, flags_or_addr, addr=None):
  358. self._checkClosed()
  359. if self._sslobj:
  360. raise ValueError("sendto not allowed on instances of %s" %
  361. self.__class__)
  362. elif addr is None:
  363. return socket.sendto(self, data, flags_or_addr)
  364. else:
  365. return socket.sendto(self, data, flags_or_addr, addr)
  366. def sendmsg(self, *args, **kwargs):
  367. # Ensure programs don't send data unencrypted if they try to
  368. # use this method.
  369. raise NotImplementedError("sendmsg not allowed on instances of %s" %
  370. self.__class__)
  371. def sendall(self, data, flags=0):
  372. self._checkClosed()
  373. if self._sslobj:
  374. if flags != 0:
  375. raise ValueError(
  376. "non-zero flags not allowed in calls to sendall() on %s" %
  377. self.__class__)
  378. try:
  379. return socket.sendall(self, data, flags)
  380. except _socket_timeout:
  381. if self.timeout == 0.0:
  382. # Raised by the stdlib on non-blocking sockets
  383. raise SSLWantWriteError("The operation did not complete (write)")
  384. raise
  385. def recv(self, buflen=1024, flags=0):
  386. self._checkClosed()
  387. if self._sslobj:
  388. if flags != 0:
  389. raise ValueError(
  390. "non-zero flags not allowed in calls to recv() on %s" %
  391. self.__class__)
  392. if buflen == 0:
  393. # https://github.com/python/cpython/commit/00915577dd84ba75016400793bf547666e6b29b5
  394. # Python #23804
  395. return b''
  396. return self.read(buflen)
  397. else:
  398. return socket.recv(self, buflen, flags)
  399. def recv_into(self, buffer, nbytes=None, flags=0):
  400. self._checkClosed()
  401. if buffer and (nbytes is None):
  402. nbytes = len(buffer)
  403. elif nbytes is None:
  404. nbytes = 1024
  405. if self._sslobj:
  406. if flags != 0:
  407. raise ValueError("non-zero flags not allowed in calls to recv_into() on %s" % self.__class__)
  408. return self.read(nbytes, buffer)
  409. else:
  410. return socket.recv_into(self, buffer, nbytes, flags)
  411. def recvfrom(self, buflen=1024, flags=0):
  412. self._checkClosed()
  413. if self._sslobj:
  414. raise ValueError("recvfrom not allowed on instances of %s" %
  415. self.__class__)
  416. else:
  417. return socket.recvfrom(self, buflen, flags)
  418. def recvfrom_into(self, buffer, nbytes=None, flags=0):
  419. self._checkClosed()
  420. if self._sslobj:
  421. raise ValueError("recvfrom_into not allowed on instances of %s" %
  422. self.__class__)
  423. else:
  424. return socket.recvfrom_into(self, buffer, nbytes, flags)
  425. def recvmsg(self, *args, **kwargs):
  426. raise NotImplementedError("recvmsg not allowed on instances of %s" %
  427. self.__class__)
  428. def recvmsg_into(self, *args, **kwargs):
  429. raise NotImplementedError("recvmsg_into not allowed on instances of "
  430. "%s" % self.__class__)
  431. def pending(self):
  432. self._checkClosed()
  433. if self._sslobj:
  434. return self._sslobj.pending()
  435. return 0
  436. def shutdown(self, how):
  437. self._checkClosed()
  438. self._sslobj = None
  439. socket.shutdown(self, how)
  440. def unwrap(self):
  441. if self._sslobj:
  442. while True:
  443. try:
  444. s = self._sslobj.shutdown()
  445. break
  446. except SSLWantReadError:
  447. if self.timeout == 0.0:
  448. return 0
  449. self._wait(self._read_event)
  450. except SSLWantWriteError:
  451. if self.timeout == 0.0:
  452. return 0
  453. self._wait(self._write_event)
  454. self._sslobj = None
  455. # The return value of shutting down the SSLObject is the
  456. # original wrapped socket, i.e., _contextawaresock. But that
  457. # object doesn't have the gevent wrapper around it so it can't
  458. # be used. We have to wrap it back up with a gevent wrapper.
  459. sock = socket(family=s.family, type=s.type, proto=s.proto, fileno=s.fileno())
  460. s.detach()
  461. return sock
  462. else:
  463. raise ValueError("No SSL wrapper around " + str(self))
  464. def _real_close(self):
  465. self._sslobj = None
  466. # self._closed = True
  467. socket._real_close(self)
  468. def do_handshake(self):
  469. """Perform a TLS/SSL handshake."""
  470. self._check_connected()
  471. while True:
  472. try:
  473. self._sslobj.do_handshake()
  474. break
  475. except SSLWantReadError:
  476. if self.timeout == 0.0:
  477. raise
  478. self._wait(self._read_event, timeout_exc=_SSLErrorHandshakeTimeout)
  479. except SSLWantWriteError:
  480. if self.timeout == 0.0:
  481. raise
  482. self._wait(self._write_event, timeout_exc=_SSLErrorHandshakeTimeout)
  483. if self._context.check_hostname:
  484. if not self.server_hostname:
  485. raise ValueError("check_hostname needs server_hostname "
  486. "argument")
  487. match_hostname(self.getpeercert(), self.server_hostname)
  488. def _real_connect(self, addr, connect_ex):
  489. if self.server_side:
  490. raise ValueError("can't connect in server-side mode")
  491. # Here we assume that the socket is client-side, and not
  492. # connected at the time of the call. We connect it, then wrap it.
  493. if self._connected:
  494. raise ValueError("attempt to connect already-connected SSLSocket!")
  495. self._sslobj = self._context._wrap_socket(self._sock, False, self.server_hostname)
  496. if self._session is not None: # 3.6
  497. self._sslobj = SSLObject(self._sslobj, owner=self, session=self._session)
  498. try:
  499. if connect_ex:
  500. rc = socket.connect_ex(self, addr)
  501. else:
  502. rc = None
  503. socket.connect(self, addr)
  504. if not rc:
  505. if self.do_handshake_on_connect:
  506. self.do_handshake()
  507. self._connected = True
  508. return rc
  509. except socket_error:
  510. self._sslobj = None
  511. raise
  512. def connect(self, addr):
  513. """Connects to remote ADDR, and then wraps the connection in
  514. an SSL channel."""
  515. self._real_connect(addr, False)
  516. def connect_ex(self, addr):
  517. """Connects to remote ADDR, and then wraps the connection in
  518. an SSL channel."""
  519. return self._real_connect(addr, True)
  520. def accept(self):
  521. """Accepts a new connection from a remote client, and returns
  522. a tuple containing that new connection wrapped with a server-side
  523. SSL channel, and the address of the remote client."""
  524. newsock, addr = socket.accept(self)
  525. newsock = self._context.wrap_socket(newsock,
  526. do_handshake_on_connect=self.do_handshake_on_connect,
  527. suppress_ragged_eofs=self.suppress_ragged_eofs,
  528. server_side=True)
  529. return newsock, addr
  530. def get_channel_binding(self, cb_type="tls-unique"):
  531. """Get channel binding data for current connection. Raise ValueError
  532. if the requested `cb_type` is not supported. Return bytes of the data
  533. or None if the data is not available (e.g. before the handshake).
  534. """
  535. if cb_type not in CHANNEL_BINDING_TYPES:
  536. raise ValueError("Unsupported channel binding type")
  537. if cb_type != "tls-unique":
  538. raise NotImplementedError("{0} channel binding type not implemented".format(cb_type))
  539. if self._sslobj is None:
  540. return None
  541. return self._sslobj.tls_unique_cb()
  542. # Python 3.2 onwards raise normal timeout errors, not SSLError.
  543. # See https://bugs.python.org/issue10272
  544. _SSLErrorReadTimeout = _socket_timeout('The read operation timed out')
  545. _SSLErrorWriteTimeout = _socket_timeout('The write operation timed out')
  546. _SSLErrorHandshakeTimeout = _socket_timeout('The handshake operation timed out')
  547. def wrap_socket(sock, keyfile=None, certfile=None,
  548. server_side=False, cert_reqs=CERT_NONE,
  549. ssl_version=PROTOCOL_SSLv23, ca_certs=None,
  550. do_handshake_on_connect=True,
  551. suppress_ragged_eofs=True,
  552. ciphers=None):
  553. return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile,
  554. server_side=server_side, cert_reqs=cert_reqs,
  555. ssl_version=ssl_version, ca_certs=ca_certs,
  556. do_handshake_on_connect=do_handshake_on_connect,
  557. suppress_ragged_eofs=suppress_ragged_eofs,
  558. ciphers=ciphers)
  559. def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv23, ca_certs=None):
  560. """Retrieve the certificate from the server at the specified address,
  561. and return it as a PEM-encoded string.
  562. If 'ca_certs' is specified, validate the server cert against it.
  563. If 'ssl_version' is specified, use it in the connection attempt."""
  564. _, _ = addr
  565. if ca_certs is not None:
  566. cert_reqs = CERT_REQUIRED
  567. else:
  568. cert_reqs = CERT_NONE
  569. s = create_connection(addr)
  570. s = wrap_socket(s, ssl_version=ssl_version,
  571. cert_reqs=cert_reqs, ca_certs=ca_certs)
  572. dercert = s.getpeercert(True)
  573. s.close()
  574. return DER_cert_to_PEM_cert(dercert)