PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib-python/modified-2.7/ssl.py

https://bitbucket.org/rokujyouhitoma/pypy/
Python | 439 lines | 364 code | 12 blank | 63 comment | 14 complexity | 294ab2767993ea93d1f1e7e842c34980 MD5 | raw file
  1. # Wrapper module for _ssl, providing some additional facilities
  2. # implemented in Python. Written by Bill Janssen.
  3. """\
  4. This module provides some more Pythonic support for SSL.
  5. Object types:
  6. SSLSocket -- subtype of socket.socket which does SSL over the socket
  7. Exceptions:
  8. SSLError -- exception raised for I/O errors
  9. Functions:
  10. cert_time_to_seconds -- convert time string used for certificate
  11. notBefore and notAfter functions to integer
  12. seconds past the Epoch (the time values
  13. returned from time.time())
  14. fetch_server_certificate (HOST, PORT) -- fetch the certificate provided
  15. by the server running on HOST at port PORT. No
  16. validation of the certificate is performed.
  17. Integer constants:
  18. SSL_ERROR_ZERO_RETURN
  19. SSL_ERROR_WANT_READ
  20. SSL_ERROR_WANT_WRITE
  21. SSL_ERROR_WANT_X509_LOOKUP
  22. SSL_ERROR_SYSCALL
  23. SSL_ERROR_SSL
  24. SSL_ERROR_WANT_CONNECT
  25. SSL_ERROR_EOF
  26. SSL_ERROR_INVALID_ERROR_CODE
  27. The following group define certificate requirements that one side is
  28. allowing/requiring from the other side:
  29. CERT_NONE - no certificates from the other side are required (or will
  30. be looked at if provided)
  31. CERT_OPTIONAL - certificates are not required, but if provided will be
  32. validated, and if validation fails, the connection will
  33. also fail
  34. CERT_REQUIRED - certificates are required, and will be validated, and
  35. if validation fails, the connection will also fail
  36. The following constants identify various SSL protocol variants:
  37. PROTOCOL_SSLv2
  38. PROTOCOL_SSLv3
  39. PROTOCOL_SSLv23
  40. PROTOCOL_TLSv1
  41. """
  42. import textwrap
  43. import _ssl # if we can't import it, let the error propagate
  44. from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
  45. from _ssl import SSLError
  46. from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
  47. from _ssl import RAND_status, RAND_egd, RAND_add
  48. from _ssl import \
  49. SSL_ERROR_ZERO_RETURN, \
  50. SSL_ERROR_WANT_READ, \
  51. SSL_ERROR_WANT_WRITE, \
  52. SSL_ERROR_WANT_X509_LOOKUP, \
  53. SSL_ERROR_SYSCALL, \
  54. SSL_ERROR_SSL, \
  55. SSL_ERROR_WANT_CONNECT, \
  56. SSL_ERROR_EOF, \
  57. SSL_ERROR_INVALID_ERROR_CODE
  58. from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1
  59. _PROTOCOL_NAMES = {
  60. PROTOCOL_TLSv1: "TLSv1",
  61. PROTOCOL_SSLv23: "SSLv23",
  62. PROTOCOL_SSLv3: "SSLv3",
  63. }
  64. try:
  65. from _ssl import PROTOCOL_SSLv2
  66. except ImportError:
  67. pass
  68. else:
  69. _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2"
  70. from socket import socket, _fileobject, error as socket_error
  71. from socket import getnameinfo as _getnameinfo
  72. import base64 # for DER-to-PEM translation
  73. import errno
  74. class SSLSocket(socket):
  75. """This class implements a subtype of socket.socket that wraps
  76. the underlying OS socket in an SSL context when necessary, and
  77. provides read and write methods over that channel."""
  78. def __init__(self, sock, keyfile=None, certfile=None,
  79. server_side=False, cert_reqs=CERT_NONE,
  80. ssl_version=PROTOCOL_SSLv23, ca_certs=None,
  81. do_handshake_on_connect=True,
  82. suppress_ragged_eofs=True, ciphers=None):
  83. socket.__init__(self, _sock=sock._sock)
  84. if certfile and not keyfile:
  85. keyfile = certfile
  86. # see if it's connected
  87. try:
  88. socket.getpeername(self)
  89. except socket_error, e:
  90. if e.errno != errno.ENOTCONN:
  91. raise
  92. # no, no connection yet
  93. self._sslobj = None
  94. else:
  95. # yes, create the SSL object
  96. self._sslobj = _ssl.sslwrap(self._sock, server_side,
  97. keyfile, certfile,
  98. cert_reqs, ssl_version, ca_certs,
  99. ciphers)
  100. if do_handshake_on_connect:
  101. self.do_handshake()
  102. self.keyfile = keyfile
  103. self.certfile = certfile
  104. self.cert_reqs = cert_reqs
  105. self.ssl_version = ssl_version
  106. self.ca_certs = ca_certs
  107. self.ciphers = ciphers
  108. self.do_handshake_on_connect = do_handshake_on_connect
  109. self.suppress_ragged_eofs = suppress_ragged_eofs
  110. self._makefile_refs = 0
  111. def read(self, len=1024):
  112. """Read up to LEN bytes and return them.
  113. Return zero-length string on EOF."""
  114. try:
  115. return self._sslobj.read(len)
  116. except SSLError, x:
  117. if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
  118. return ''
  119. else:
  120. raise
  121. def write(self, data):
  122. """Write DATA to the underlying SSL channel. Returns
  123. number of bytes of DATA actually transmitted."""
  124. return self._sslobj.write(data)
  125. def getpeercert(self, binary_form=False):
  126. """Returns a formatted version of the data in the
  127. certificate provided by the other end of the SSL channel.
  128. Return None if no certificate was provided, {} if a
  129. certificate was provided, but not validated."""
  130. return self._sslobj.peer_certificate(binary_form)
  131. def cipher(self):
  132. if not self._sslobj:
  133. return None
  134. else:
  135. return self._sslobj.cipher()
  136. def send(self, data, flags=0):
  137. if self._sslobj:
  138. if flags != 0:
  139. raise ValueError(
  140. "non-zero flags not allowed in calls to send() on %s" %
  141. self.__class__)
  142. while True:
  143. try:
  144. v = self._sslobj.write(data)
  145. except SSLError, x:
  146. if x.args[0] == SSL_ERROR_WANT_READ:
  147. return 0
  148. elif x.args[0] == SSL_ERROR_WANT_WRITE:
  149. return 0
  150. else:
  151. raise
  152. else:
  153. return v
  154. else:
  155. return self._sock.send(data, flags)
  156. def sendto(self, data, flags_or_addr, addr=None):
  157. if self._sslobj:
  158. raise ValueError("sendto not allowed on instances of %s" %
  159. self.__class__)
  160. elif addr is None:
  161. return self._sock.sendto(data, flags_or_addr)
  162. else:
  163. return self._sock.sendto(data, flags_or_addr, addr)
  164. def sendall(self, data, flags=0):
  165. if self._sslobj:
  166. if flags != 0:
  167. raise ValueError(
  168. "non-zero flags not allowed in calls to sendall() on %s" %
  169. self.__class__)
  170. amount = len(data)
  171. count = 0
  172. while (count < amount):
  173. v = self.send(data[count:])
  174. count += v
  175. return amount
  176. else:
  177. return socket.sendall(self, data, flags)
  178. def recv(self, buflen=1024, flags=0):
  179. if self._sslobj:
  180. if flags != 0:
  181. raise ValueError(
  182. "non-zero flags not allowed in calls to recv() on %s" %
  183. self.__class__)
  184. return self.read(buflen)
  185. else:
  186. return self._sock.recv(buflen, flags)
  187. def recv_into(self, buffer, nbytes=None, flags=0):
  188. if buffer and (nbytes is None):
  189. nbytes = len(buffer)
  190. elif nbytes is None:
  191. nbytes = 1024
  192. if self._sslobj:
  193. if flags != 0:
  194. raise ValueError(
  195. "non-zero flags not allowed in calls to recv_into() on %s" %
  196. self.__class__)
  197. tmp_buffer = self.read(nbytes)
  198. v = len(tmp_buffer)
  199. buffer[:v] = tmp_buffer
  200. return v
  201. else:
  202. return self._sock.recv_into(buffer, nbytes, flags)
  203. def recvfrom(self, buflen=1024, flags=0):
  204. if self._sslobj:
  205. raise ValueError("recvfrom not allowed on instances of %s" %
  206. self.__class__)
  207. else:
  208. return self._sock.recvfrom(buflen, flags)
  209. def recvfrom_into(self, buffer, nbytes=None, flags=0):
  210. if self._sslobj:
  211. raise ValueError("recvfrom_into not allowed on instances of %s" %
  212. self.__class__)
  213. else:
  214. return self._sock.recvfrom_into(buffer, nbytes, flags)
  215. def pending(self):
  216. if self._sslobj:
  217. return self._sslobj.pending()
  218. else:
  219. return 0
  220. def unwrap(self):
  221. if self._sslobj:
  222. s = self._sslobj.shutdown()
  223. self._sslobj = None
  224. return s
  225. else:
  226. raise ValueError("No SSL wrapper around " + str(self))
  227. def shutdown(self, how):
  228. self._sslobj = None
  229. socket.shutdown(self, how)
  230. def close(self):
  231. if self._makefile_refs < 1:
  232. self._sslobj = None
  233. socket.close(self)
  234. else:
  235. self._makefile_refs -= 1
  236. def do_handshake(self):
  237. """Perform a TLS/SSL handshake."""
  238. self._sslobj.do_handshake()
  239. def connect(self, addr):
  240. """Connects to remote ADDR, and then wraps the connection in
  241. an SSL channel."""
  242. # Here we assume that the socket is client-side, and not
  243. # connected at the time of the call. We connect it, then wrap it.
  244. if self._sslobj:
  245. raise ValueError("attempt to connect already-connected SSLSocket!")
  246. socket.connect(self, addr)
  247. self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile,
  248. self.cert_reqs, self.ssl_version,
  249. self.ca_certs, self.ciphers)
  250. if self.do_handshake_on_connect:
  251. self.do_handshake()
  252. def accept(self):
  253. """Accepts a new connection from a remote client, and returns
  254. a tuple containing that new connection wrapped with a server-side
  255. SSL channel, and the address of the remote client."""
  256. newsock, addr = socket.accept(self)
  257. return (SSLSocket(newsock,
  258. keyfile=self.keyfile,
  259. certfile=self.certfile,
  260. server_side=True,
  261. cert_reqs=self.cert_reqs,
  262. ssl_version=self.ssl_version,
  263. ca_certs=self.ca_certs,
  264. ciphers=self.ciphers,
  265. do_handshake_on_connect=self.do_handshake_on_connect,
  266. suppress_ragged_eofs=self.suppress_ragged_eofs),
  267. addr)
  268. def makefile(self, mode='r', bufsize=-1):
  269. """Make and return a file-like object that
  270. works with the SSL connection. Just use the code
  271. from the socket module."""
  272. self._makefile_refs += 1
  273. # close=True so as to decrement the reference count when done with
  274. # the file-like object.
  275. return _fileobject(self, mode, bufsize, close=True)
  276. def wrap_socket(sock, keyfile=None, certfile=None,
  277. server_side=False, cert_reqs=CERT_NONE,
  278. ssl_version=PROTOCOL_SSLv23, ca_certs=None,
  279. do_handshake_on_connect=True,
  280. suppress_ragged_eofs=True, ciphers=None):
  281. return SSLSocket(sock, keyfile=keyfile, certfile=certfile,
  282. server_side=server_side, cert_reqs=cert_reqs,
  283. ssl_version=ssl_version, ca_certs=ca_certs,
  284. do_handshake_on_connect=do_handshake_on_connect,
  285. suppress_ragged_eofs=suppress_ragged_eofs,
  286. ciphers=ciphers)
  287. # some utility functions
  288. def cert_time_to_seconds(cert_time):
  289. """Takes a date-time string in standard ASN1_print form
  290. ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return
  291. a Python time value in seconds past the epoch."""
  292. import time
  293. return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT"))
  294. PEM_HEADER = "-----BEGIN CERTIFICATE-----"
  295. PEM_FOOTER = "-----END CERTIFICATE-----"
  296. def DER_cert_to_PEM_cert(der_cert_bytes):
  297. """Takes a certificate in binary DER format and returns the
  298. PEM version of it as a string."""
  299. if hasattr(base64, 'standard_b64encode'):
  300. # preferred because older API gets line-length wrong
  301. f = base64.standard_b64encode(der_cert_bytes)
  302. return (PEM_HEADER + '\n' +
  303. textwrap.fill(f, 64) + '\n' +
  304. PEM_FOOTER + '\n')
  305. else:
  306. return (PEM_HEADER + '\n' +
  307. base64.encodestring(der_cert_bytes) +
  308. PEM_FOOTER + '\n')
  309. def PEM_cert_to_DER_cert(pem_cert_string):
  310. """Takes a certificate in ASCII PEM format and returns the
  311. DER-encoded version of it as a byte sequence"""
  312. if not pem_cert_string.startswith(PEM_HEADER):
  313. raise ValueError("Invalid PEM encoding; must start with %s"
  314. % PEM_HEADER)
  315. if not pem_cert_string.strip().endswith(PEM_FOOTER):
  316. raise ValueError("Invalid PEM encoding; must end with %s"
  317. % PEM_FOOTER)
  318. d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)]
  319. return base64.decodestring(d)
  320. def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None):
  321. """Retrieve the certificate from the server at the specified address,
  322. and return it as a PEM-encoded string.
  323. If 'ca_certs' is specified, validate the server cert against it.
  324. If 'ssl_version' is specified, use it in the connection attempt."""
  325. host, port = addr
  326. if (ca_certs is not None):
  327. cert_reqs = CERT_REQUIRED
  328. else:
  329. cert_reqs = CERT_NONE
  330. s = wrap_socket(socket(), ssl_version=ssl_version,
  331. cert_reqs=cert_reqs, ca_certs=ca_certs)
  332. s.connect(addr)
  333. dercert = s.getpeercert(True)
  334. s.close()
  335. return DER_cert_to_PEM_cert(dercert)
  336. def get_protocol_name(protocol_code):
  337. return _PROTOCOL_NAMES.get(protocol_code, '<unknown>')
  338. # a replacement for the old socket.ssl function
  339. def sslwrap_simple(sock, keyfile=None, certfile=None):
  340. """A replacement for the old socket.ssl function. Designed
  341. for compability with Python 2.5 and earlier. Will disappear in
  342. Python 3.0."""
  343. if hasattr(sock, "_sock"):
  344. sock = sock._sock
  345. ssl_sock = _ssl.sslwrap(sock, 0, keyfile, certfile, CERT_NONE,
  346. PROTOCOL_SSLv23, None)
  347. try:
  348. sock.getpeername()
  349. except socket_error:
  350. # no, no connection yet
  351. pass
  352. else:
  353. # yes, do the handshake
  354. ssl_sock.do_handshake()
  355. return ssl_sock