Advertisement
Guest User

Untitled

a guest
Aug 29th, 2013
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.59 KB | None | 0 0
  1. this patch series consists of 1 patches.
  2.  
  3. [?1034hCc:
  4. displaying [PATCH] https: support tls sni (server name indication) for https urls (issue3090) ...
  5. Content-Type: text/plain; charset="us-ascii"
  6. MIME-Version: 1.0
  7. Content-Transfer-Encoding: 7bit
  8. Subject: [PATCH] https: support tls sni (server name indication) for https
  9. urls (issue3090)
  10. X-Mercurial-Node: 1521e79acdcd4fbfea77dc4d95be2106508934d5
  11. Message-Id: <1521e79acdcd4fbfea77.1377772380@localhost>
  12. User-Agent: Mercurial-patchbomb/2.4.2
  13. Date: Thu, 29 Aug 2013 04:33:00 -0600
  14. From: Alex Orange <crazycasta@gmail.com>
  15. To: mercurial-devel@selenic.com
  16.  
  17. # HG changeset patch
  18. # User Alex Orange <crazycasta@gmail.com>
  19. # Date 1377769698 21600
  20. # Node ID 1521e79acdcd4fbfea77dc4d95be2106508934d5
  21. # Parent d4a0055af149cdea20b3136b66cae8a24b2e2a98
  22. https: support tls sni (server name indication) for https urls (issue3090)
  23.  
  24. SNI is a common way of sharing servers across multiple domains using separate
  25. SSL certificates. Python 2.x does not, and will not, support SNI according to:
  26. http://bugs.python.org/issue5639#msg192234. In order to support SNI pyOpenSSL
  27. and pyasn1 have been used to emulate Python's SSLSocket object (the one
  28. returned by wrap_socket). Additionally, changes are made to code in httpclient,
  29. sslutil, and url to pass the server hostname to the relavent wrap_socket
  30. wrapper function.
  31.  
  32. The research I did led me to the conclusion that an OpenSSL based solution
  33. would best replicate that existing python ssl object. As opposed to a GNUTLS
  34. solution like PyGnuTLS (https://gitorious.org/pygnutls). The two packages I
  35. found that perform the basic functions of the python ssl object are pyOpenSSL
  36. (http://pythonhosted.org/pyOpenSSL/) and M2Crypto
  37. (http://www.heikkitoivonen.net/m2crypto/). M2Crypto does not support sending
  38. the host name as far as I can tell, which leaves pyOpenSSL. The shortcoming of
  39. both of these libraries is that they do not provide give the subjectAltName
  40. subobjects as separate objects. They give either the DER encoded raw data or
  41. an openssl command line style string "DNS:a.b.com, DNS:c.d.com, ...". I did not
  42. want to parse this string in case a certificate came up with a dNSName had the
  43. form 'a.b.com, DNS:c.d.com' which could conceivably lead to a security problem.
  44. In order to handle this problem I used pyasn1 to parse the subjectAltName data
  45. along with code taken from ndg-httpsclient. There appears to also be an
  46. way to do this directly through python's ssl module with an undocumented
  47. function called _test_decode_cert. However this would involve writing
  48. certificates to temporary files and then reading them back in. This seems like
  49. a bad idea both because the function is undocumented (and therefore vulnerable
  50. to going away without warning) and a possible security risk: writing to files
  51. and then reading them back in. Finally, to make the all of this as unobtrusive
  52. as possible I wrapped this functionality into a single class that emulates the
  53. python ssl class called SocketWrapper in opensslwrap.py.
  54.  
  55. Finally, imports of pyOpenSSL and pyasn1 are tried before the import of ssl in
  56. httpclient/socketutil.py and sslutil.py. This prefers the use of this scheme
  57. over the built-in ssl module for those that have the supporting packages. The
  58. imports take the form of from a import b so as to force immediate import since
  59. pyasn1 in particular is not immediately used.
  60.  
  61. diff -r d4a0055af149 -r 1521e79acdcd mercurial/sslutil.py
  62. --- a/mercurial/sslutil.py Fri Aug 23 16:16:22 2013 -0400
  63. +++ b/mercurial/sslutil.py Thu Aug 29 03:48:18 2013 -0600
  64. @@ -11,34 +11,51 @@
  65. from mercurial import util
  66. from mercurial.i18n import _
  67. try:
  68. - # avoid using deprecated/broken FakeSocket in python 2.6
  69. - import ssl
  70. - CERT_REQUIRED = ssl.CERT_REQUIRED
  71. + # Force the import
  72. + from ssl_sni import openssl
  73. +
  74. + CERT_REQUIRED = openssl.CERT_REQUIRED
  75. def ssl_wrap_socket(sock, keyfile, certfile,
  76. - cert_reqs=ssl.CERT_NONE, ca_certs=None):
  77. - sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
  78. - cert_reqs=cert_reqs, ca_certs=ca_certs,
  79. - ssl_version=ssl.PROTOCOL_SSLv3)
  80. - # check if wrap_socket failed silently because socket had been closed
  81. - # - see http://bugs.python.org/issue13721
  82. - if not sslsocket.cipher():
  83. - raise util.Abort(_('ssl connection failed'))
  84. + cert_reqs=openssl.CERT_NONE, ca_certs=None,
  85. + server_hostname=None):
  86. + sslsocket = openssl.wrap_socket(sock, keyfile, certfile,
  87. + cert_reqs=cert_reqs,
  88. + ca_certs=ca_certs,
  89. + server_hostname=server_hostname)
  90. return sslsocket
  91. except ImportError:
  92. - CERT_REQUIRED = 2
  93. + try:
  94. + # avoid using deprecated/broken FakeSocket in python 2.6
  95. + import ssl
  96. + CERT_REQUIRED = ssl.CERT_REQUIRED
  97. + def ssl_wrap_socket(sock, keyfile, certfile,
  98. + cert_reqs=ssl.CERT_NONE, ca_certs=None,
  99. + server_hostname=None):
  100. + sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
  101. + cert_reqs=cert_reqs, ca_certs=ca_certs,
  102. + ssl_version=ssl.PROTOCOL_SSLv3)
  103. + # check if wrap_socket failed silently because socket had been
  104. + # closed
  105. + # - see http://bugs.python.org/issue13721
  106. + if not sslsocket.cipher():
  107. + raise util.Abort(_('ssl connection failed'))
  108. + return sslsocket
  109. + except ImportError:
  110. + CERT_REQUIRED = 2
  111.  
  112. - import socket, httplib
  113. + import socket, httplib
  114.  
  115. - def ssl_wrap_socket(sock, key_file, cert_file,
  116. - cert_reqs=CERT_REQUIRED, ca_certs=None):
  117. - if not util.safehasattr(socket, 'ssl'):
  118. - raise util.Abort(_('Python SSL support not found'))
  119. - if ca_certs:
  120. - raise util.Abort(_(
  121. - 'certificate checking requires Python 2.6'))
  122. + def ssl_wrap_socket(sock, key_file, cert_file,
  123. + cert_reqs=CERT_REQUIRED, ca_certs=None,
  124. + server_hostname=None):
  125. + if not util.safehasattr(socket, 'ssl'):
  126. + raise util.Abort(_('Python SSL support not found'))
  127. + if ca_certs:
  128. + raise util.Abort(_(
  129. + 'certificate checking requires Python 2.6'))
  130.  
  131. - ssl = socket.ssl(sock, key_file, cert_file)
  132. - return httplib.FakeSocket(sock, ssl)
  133. + ssl = socket.ssl(sock, key_file, cert_file)
  134. + return httplib.FakeSocket(sock, ssl)
  135.  
  136. def _verifycert(cert, hostname):
  137. '''Verify that cert (in socket.getpeercert() format) matches hostname.
  138. @@ -115,9 +132,14 @@
  139. self.ui.warn(_("warning: certificate for %s can't be verified "
  140. "(Python too old)\n") % host)
  141. return
  142. + try:
  143. + # work around http://bugs.python.org/issue13721
  144. + if not sock.cipher():
  145. + raise util.Abort(_('%s ssl connection error') % host)
  146. + except AttributeError:
  147. + # This is not the ssl object you are looking for
  148. + pass
  149.  
  150. - if not sock.cipher(): # work around http://bugs.python.org/issue13721
  151. - raise util.Abort(_('%s ssl connection error') % host)
  152. try:
  153. peercert = sock.getpeercert(True)
  154. peercert2 = sock.getpeercert()
  155. diff -r d4a0055af149 -r 1521e79acdcd mercurial/url.py
  156. --- a/mercurial/url.py Fri Aug 23 16:16:22 2013 -0400
  157. +++ b/mercurial/url.py Thu Aug 29 03:48:18 2013 -0600
  158. @@ -181,7 +181,8 @@
  159. self.sock.connect((self.host, self.port))
  160. if _generic_proxytunnel(self):
  161. # we do not support client X.509 certificates
  162. - self.sock = sslutil.ssl_wrap_socket(self.sock, None, None)
  163. + self.sock = sslutil.ssl_wrap_socket(self.sock, None, None,
  164. + server_hostname=self.host)
  165. else:
  166. keepalive.HTTPConnection.connect(self)
  167.  
  168. @@ -338,7 +339,7 @@
  169. _generic_proxytunnel(self)
  170. host = self.realhostport.rsplit(':', 1)[0]
  171. self.sock = sslutil.ssl_wrap_socket(
  172. - self.sock, self.key_file, self.cert_file,
  173. + self.sock, self.key_file, self.cert_file, server_hostname=host,
  174. **sslutil.sslkwargs(self.ui, host))
  175. sslutil.validator(self.ui, host)(self.sock)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement