[Python-modules-commits] [twisted] 01/06: New upstream version 16.6.0

Free Ekanayaka freee at moszumanska.debian.org
Sat Nov 26 12:01:42 UTC 2016


This is an automated email from the git hooks/post-receive script.

freee pushed a commit to branch master
in repository twisted.

commit 805e9d3ed266278d9ae1285f686379a200ea9098
Author: Free Ekanayaka <freee at debian.org>
Date:   Sat Nov 26 06:23:37 2016 +0000

    New upstream version 16.6.0
---
 NEWS                                               |  107 +
 PKG-INFO                                           |    2 +-
 README.rst                                         |    7 +-
 .../development/policy/compatibility-policy.rst    |    4 +-
 docs/historic/Quotes/Twisted-16.6                  |   10 +
 docs/installation/howto/optional.rst               |    2 -
 src/Twisted.egg-info/PKG-INFO                      |    2 +-
 src/Twisted.egg-info/SOURCES.txt                   |    3 +
 src/Twisted.egg-info/requires.txt                  |   16 +-
 src/twisted/__main__.py                            |   16 +
 src/twisted/_version.py                            |    2 +-
 src/twisted/conch/scripts/cftp.py                  |    3 +-
 src/twisted/conch/scripts/ckeygen.py               |   69 +-
 src/twisted/conch/ssh/common.py                    |   61 +-
 src/twisted/conch/ssh/keys.py                      |  246 ++-
 src/twisted/conch/test/keydata.py                  |   67 +
 src/twisted/conch/test/test_ckeygen.py             |  141 +-
 src/twisted/conch/test/test_keys.py                |  173 ++
 src/twisted/conch/test/test_ssh.py                 |   61 +-
 src/twisted/internet/_sslverify.py                 |    3 +
 src/twisted/internet/base.py                       |    4 +
 src/twisted/internet/defer.py                      |   55 +-
 .../internet/iocpreactor/iocpsupport/acceptex.pxi  |    8 +-
 .../internet/iocpreactor/iocpsupport/connectex.pxi |    8 +-
 .../internet/iocpreactor/iocpsupport/iocpsupport.c | 2144 +++++++++++---------
 .../iocpreactor/iocpsupport/iocpsupport.pyx        |   67 +-
 .../internet/iocpreactor/iocpsupport/wsarecv.pxi   |   14 +-
 .../internet/iocpreactor/iocpsupport/wsasend.pxi   |    7 +-
 src/twisted/internet/protocol.py                   |    6 +
 src/twisted/internet/serialport.py                 |    2 +
 src/twisted/internet/ssl.py                        |    4 +-
 src/twisted/internet/test/_awaittests.py.3only     |   49 +-
 src/twisted/internet/test/_yieldfromtests.py.3only |   42 +-
 src/twisted/internet/test/connectionmixins.py      |    2 +-
 src/twisted/internet/test/test_unix.py             |    2 +-
 src/twisted/internet/udp.py                        |    2 +
 src/twisted/internet/wxsupport.py                  |   12 +-
 src/twisted/pair/tuntap.py                         |    2 +-
 src/twisted/persisted/dirdbm.py                    |  224 +-
 src/twisted/protocols/ftp.py                       |    4 +-
 src/twisted/protocols/postfix.py                   |    4 +-
 src/twisted/protocols/sip.py                       |  291 ++-
 src/twisted/python/_setup.py                       |   43 +-
 src/twisted/python/compat.py                       |   19 +
 src/twisted/python/components.py                   |    3 +
 src/twisted/python/log.py                          |    7 +
 src/twisted/python/test/test_release.py            |   24 +
 src/twisted/python/test/test_setup.py              |   14 +-
 src/twisted/test/test_defer.py                     |   26 +-
 src/twisted/test/test_dirdbm.py                    |  153 +-
 src/twisted/test/test_main.py                      |   47 +
 src/twisted/test/test_nooldstyle.py                |   11 +
 src/twisted/test/test_postfix.py                   |    2 +-
 src/twisted/test/test_sip.py                       |   77 +-
 src/twisted/web/_http2.py                          |   28 +-
 src/twisted/web/_newclient.py                      |   13 +
 src/twisted/web/test/test_http2.py                 |   92 +-
 src/twisted/web/test/test_newclient.py             |  132 ++
 src/twisted/words/im/interfaces.py                 |   36 +
 src/twisted/words/im/ircsupport.py                 |   82 +-
 src/twisted/words/protocols/irc.py                 |   59 +-
 src/twisted/words/service.py                       |  173 +-
 src/twisted/words/test/test_irc.py                 |  145 +-
 src/twisted/words/test/test_irc_service.py         |  100 +-
 src/twisted/words/test/test_ircsupport.py          |  218 +-
 src/twisted/words/test/test_service.py             |   95 +-
 tox.ini                                            |   35 +-
 67 files changed, 3737 insertions(+), 1845 deletions(-)

diff --git a/NEWS b/NEWS
index 5435ed7..4768aac 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,113 @@
 Ticket numbers in this file can be looked up by visiting
 http://twistedmatrix.com/trac/ticket/<number>
 
+Twisted Core 16.6.0 (2016-11-17)
+================================
+
+Features
+--------
+ - The twist script can now be run by invoking python -m twisted.
+   (#8657)
+ - twisted.protocols.sip has been ported to Python 3. (#8669)
+ - twisted.persisted.dirdbm has been ported to Python 3. (#8888)
+
+Bugfixes
+--------
+ - twisted.internet.defer.Deferred now implements send, not __send__,
+   which means that it is now a conforming generator. (#8861)
+ - The IOCP reactor no longer transmits the contents of uninitialized
+   memory when writing large amounts of data. (#8870)
+ - Deferreds awaited/yielded from in a
+   twisted.internet.defer.ensureDeferred wrapped coroutine will now
+   properly raise exceptions. Additionally, it more closely models
+   asyncio.ensure_future and will pass through Deferreds. (#8878)
+ - Deferreds that are paused or chained on other Deferreds will now
+   return a result when yielded/awaited in a twisted.internet.defer
+   .ensureDeferred-wrapped coroutine, instead of returning the
+   Deferred it was chained to. (#8890)
+
+Improved Documentation
+----------------------
+ - twisted.test.proto_helpers is now explicitly covered by the
+   compatibility policy. (#8857)
+
+Other
+-----
+ - #8281, #8823, #8862
+
+
+Twisted Conch 16.6.0 (2016-11-17)
+=================================
+
+Features
+--------
+ - twisted.conch.ssh.keys supports ECDSA keys (#8798)
+ - scripts/ckeygen can now generate ecdsa keys. (#8828)
+ - ckeygen has been ported to Python 3 (#8855)
+
+Deprecations and Removals
+-------------------------
+ - twisted.conch.ssh no longer uses gmpy, if available. gmpy is
+   unmaintained, does not have binary wheels for any platforms, and an
+   alternative for higher performance is available in the form of
+   PyPy. (#8079)
+
+
+Twisted Mail 16.6.0 (2016-11-17)
+================================
+
+No significant changes have been made for this release.
+
+
+Twisted Names 16.6.0 (2016-11-17)
+=================================
+
+No significant changes have been made for this release.
+
+
+Twisted News 16.6.0 (2016-11-17)
+================================
+
+No significant changes have been made for this release.
+
+
+Twisted Pair 16.6.0 (2016-11-17)
+================================
+
+No significant changes have been made for this release.
+
+
+Twisted Runner 16.6.0 (2016-11-17)
+==================================
+
+No significant changes have been made for this release.
+
+
+Twisted Web 16.6.0 (2016-11-17)
+===============================
+
+Features
+--------
+ - twisted.web.server.Site's HTTP/2 server support now emits vastly
+   fewer WINDOW_UPDATE frames than previously. (#8681)
+
+Bugfixes
+--------
+ - twisted.web.Agent now tolerates receiving unexpected status codes
+   in the 100 range by discarding them, which is what RFC 7231
+   recommends doing. (#8885)
+ - twisted.web._http.H2Stream's getHost and getPeer implementations
+   now actually return the host and peer instead of None. (#8893)
+
+
+Twisted Words 16.6.0 (2016-11-17)
+=================================
+
+Features
+--------
+ - twisted.words.protocols.irc has been ported to Python 3 (#6320)
+
+
 Twisted Core 16.5.0 (2016-10-28)
 ================================
 
diff --git a/PKG-INFO b/PKG-INFO
index 8941150..63044e3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Twisted
-Version: 16.5.0
+Version: 16.6.0
 Summary: An asynchronous networking framework written in Python
 Home-page: http://twistedmatrix.com/
 Author: Glyph Lefkowitz
diff --git a/README.rst b/README.rst
index 2ff8e0e..e957b93 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,4 @@
-Twisted 16.5.0
+Twisted 16.6.0
 ==============
 
 |pypi|
@@ -8,10 +8,9 @@ Twisted 16.5.0
 
 .. code::
 
-    <runciter> it's a consultancy about nothing
-    <meejah> we could call it Scrumfeld
+    <derwolfe> Twisted - thank you for continuing to be fun to use and relatively easy to test 😃
 
-For information on what's new in Twisted 16.5.0, see the `NEWS <NEWS>`_ file that comes with the distribution.
+For information on what's new in Twisted 16.6.0, see the `NEWS <NEWS>`_ file that comes with the distribution.
 
 
 What is this?
diff --git a/docs/core/development/policy/compatibility-policy.rst b/docs/core/development/policy/compatibility-policy.rst
index be0197a..d38af93 100644
--- a/docs/core/development/policy/compatibility-policy.rst
+++ b/docs/core/development/policy/compatibility-policy.rst
@@ -130,8 +130,10 @@ Test Changes
 No code or data in a test package should be imported or used by a non-test package within Twisted.
 By doing so, there's no chance anything could access these objects by going through the public API.
 
-Test code and test helpers are considered private API and it should be imported outside
+Test code and test helpers are considered private API and should not be imported outside
 of the Twisted testing infrastructure.
+As an exception to this, :api:`twisted.test.proto_helpers` is considered a public API
+(see `#6435 <https://twistedmatrix.com/trac/ticket/6435>`_ for more discussion).
 
 
 Private Changes
diff --git a/docs/historic/Quotes/Twisted-16.6 b/docs/historic/Quotes/Twisted-16.6
new file mode 100644
index 0000000..acb30ad
--- /dev/null
+++ b/docs/historic/Quotes/Twisted-16.6
@@ -0,0 +1,10 @@
+<runciter> it appears that i've been banned from most servers
+<@glyph> runciter: you probably joined too many channels from the same nick / IP
+<runciter> glyph: yep :(  since this currently in the "dumb hack" stage of development i figured my code would blow up first
+<@glyph> runciter: that is a common problem with first-run Twisted services
+<@glyph> runciter: it's more likely you'll knock over the service you're talking to than that you'll crash
+<runciter> glyph: why does it have to work so well
+<runciter> glyph: this was never a problem with gevent
+%
+<derwolfe> Twisted - thank you for continuing to be fun to use and relatively easy to test 😃
+%
diff --git a/docs/installation/howto/optional.rst b/docs/installation/howto/optional.rst
index 8ba40b1..409ab9e 100644
--- a/docs/installation/howto/optional.rst
+++ b/docs/installation/howto/optional.rst
@@ -30,7 +30,6 @@ The following optional dependencies are supported:
     * `idna`_
 
 * **conch** - packages for working with conch/SSH.
-    * `gmpy`_
     * `pyasn1`_
     * `cryptography`_
 
@@ -57,7 +56,6 @@ The following optional dependencies are supported:
 .. _pydoctor: https://pypi.python.org/pypi/pydoctor
 .. _pyOpenSSL: https://pypi.python.org/pypi/pyOpenSSL
 .. _service_identity: https://pypi.python.org/pypi/service_identity
-.. _gmpy: https://pypi.python.org/pypi/gmpy/1.17
 .. _pyasn1: https://pypi.python.org/pypi/pyasn1
 .. _cryptography: https://pypi.python.org/pypi/cryptography
 .. _SOAPpy: https://pypi.python.org/pypi/SOAPpy
diff --git a/src/Twisted.egg-info/PKG-INFO b/src/Twisted.egg-info/PKG-INFO
index 8941150..63044e3 100644
--- a/src/Twisted.egg-info/PKG-INFO
+++ b/src/Twisted.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Twisted
-Version: 16.5.0
+Version: 16.6.0
 Summary: An asynchronous networking framework written in Python
 Home-page: http://twistedmatrix.com/
 Author: Glyph Lefkowitz
diff --git a/src/Twisted.egg-info/SOURCES.txt b/src/Twisted.egg-info/SOURCES.txt
index 4eae3c8..eeea648 100644
--- a/src/Twisted.egg-info/SOURCES.txt
+++ b/src/Twisted.egg-info/SOURCES.txt
@@ -400,6 +400,7 @@ docs/historic/Quotes/Twisted-16.2
 docs/historic/Quotes/Twisted-16.3
 docs/historic/Quotes/Twisted-16.4
 docs/historic/Quotes/Twisted-16.5
+docs/historic/Quotes/Twisted-16.6
 docs/historic/Quotes/Twisted-2.0
 docs/historic/Quotes/Twisted-2.1
 docs/historic/Quotes/Twisted-2.2
@@ -589,6 +590,7 @@ src/Twisted.egg-info/not-zip-safe
 src/Twisted.egg-info/requires.txt
 src/Twisted.egg-info/top_level.txt
 src/twisted/__init__.py
+src/twisted/__main__.py
 src/twisted/_version.py
 src/twisted/copyright.py
 src/twisted/plugin.py
@@ -1235,6 +1237,7 @@ src/twisted/test/test_lockfile.py
 src/twisted/test/test_log.py
 src/twisted/test/test_logfile.py
 src/twisted/test/test_loopback.py
+src/twisted/test/test_main.py
 src/twisted/test/test_memcache.py
 src/twisted/test/test_modules.py
 src/twisted/test/test_monkey.py
diff --git a/src/Twisted.egg-info/requires.txt b/src/Twisted.egg-info/requires.txt
index 20da55d..63dc33b 100644
--- a/src/Twisted.egg-info/requires.txt
+++ b/src/Twisted.egg-info/requires.txt
@@ -6,17 +6,15 @@ incremental >= 16.10.1
 pyopenssl >= 16.0.0
 service_identity
 idna >= 0.6
-gmpy
 pyasn1
 cryptography >= 0.9.1
 appdirs >= 1.4.0
 soappy
 pyserial
-h2 >= 2.3.0, < 3.0
+h2 >= 2.5.0, < 3.0
 priority >= 1.1.0, < 2.0
 
 [conch]
-gmpy
 pyasn1
 cryptography >= 0.9.1
 appdirs >= 1.4.0
@@ -30,21 +28,22 @@ twistedchecker >= 0.4.0
 pydoctor >= 16.2.0
 
 [http2]
-h2 >= 2.3.0, < 3.0
+h2 >= 2.5.0, < 3.0
 priority >= 1.1.0, < 2.0
 
 [osx_platform]
-pyobjc
+pyobjc-core
+pyobjc-framework-CFNetwork
+pyobjc-framework-Cocoa
 pyopenssl >= 16.0.0
 service_identity
 idna >= 0.6
-gmpy
 pyasn1
 cryptography >= 0.9.1
 appdirs >= 1.4.0
 soappy
 pyserial
-h2 >= 2.3.0, < 3.0
+h2 >= 2.5.0, < 3.0
 priority >= 1.1.0, < 2.0
 
 [serial]
@@ -63,11 +62,10 @@ pypiwin32
 pyopenssl >= 16.0.0
 service_identity
 idna >= 0.6
-gmpy
 pyasn1
 cryptography >= 0.9.1
 appdirs >= 1.4.0
 soappy
 pyserial
-h2 >= 2.3.0, < 3.0
+h2 >= 2.5.0, < 3.0
 priority >= 1.1.0, < 2.0
diff --git a/src/twisted/__main__.py b/src/twisted/__main__.py
new file mode 100644
index 0000000..16ed6ce
--- /dev/null
+++ b/src/twisted/__main__.py
@@ -0,0 +1,16 @@
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+# Make the twisted module executable with the default behaviour of
+# running twist.
+# This is not a docstring to avoid changing the string output of twist.
+
+from __future__ import division, absolute_import
+
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+    sys.exit(
+        load_entry_point('Twisted', 'console_scripts', 'twist')()
+    )
diff --git a/src/twisted/_version.py b/src/twisted/_version.py
index b96bc95..216bf39 100644
--- a/src/twisted/_version.py
+++ b/src/twisted/_version.py
@@ -7,5 +7,5 @@ Provides Twisted version information.
 
 from incremental import Version
 
-__version__ = Version('Twisted', 16, 5, 0)
+__version__ = Version('Twisted', 16, 6, 0)
 __all__ = ["__version__"]
diff --git a/src/twisted/conch/scripts/cftp.py b/src/twisted/conch/scripts/cftp.py
index 832f700..bfd95ff 100644
--- a/src/twisted/conch/scripts/cftp.py
+++ b/src/twisted/conch/scripts/cftp.py
@@ -868,7 +868,7 @@ version                         Print the SFTP version.
         else:
             return ret[0], ret[1]
 
-StdioClient.__dict__['cmd_?'] = StdioClient.cmd_HELP
+setattr(StdioClient, 'cmd_?', StdioClient.cmd_HELP)
 
 class SSHConnection(connection.SSHConnection):
     def serviceStarted(self):
@@ -928,4 +928,3 @@ class SSHSession(channel.SSHChannel):
 
 if __name__ == '__main__':
     run()
-
diff --git a/src/twisted/conch/scripts/ckeygen.py b/src/twisted/conch/scripts/ckeygen.py
index 3cd27c8..64e630b 100644
--- a/src/twisted/conch/scripts/ckeygen.py
+++ b/src/twisted/conch/scripts/ckeygen.py
@@ -9,6 +9,7 @@ Implementation module for the `ckeygen` command.
 from __future__ import print_function
 
 import sys, os, getpass, socket
+from functools import wraps
 if getpass.getpass == getpass.unix_getpass:
     try:
         import termios # hack around broken termios
@@ -19,6 +20,19 @@ if getpass.getpass == getpass.unix_getpass:
 
 from twisted.conch.ssh import keys
 from twisted.python import failure, filepath, log, usage
+from twisted.python.compat import raw_input, _PY3
+
+
+
+supportedKeyTypes = dict()
+def _keyGenerator(keyType):
+    def assignkeygenerator(keygenerator):
+        @wraps(keygenerator)
+        def wrapper(*args, **kwargs):
+            return keygenerator(*args, **kwargs)
+        supportedKeyTypes[keyType] = wrapper
+        return wrapper
+    return assignkeygenerator
 
 
 
@@ -28,7 +42,7 @@ class GeneralOptions(usage.Options):
 
     longdesc = "ckeygen manipulates public/private keys in various ways."
 
-    optParameters = [['bits', 'b', 1024, 'Number of bits in the key to create.'],
+    optParameters = [['bits', 'b', None, 'Number of bits in the key to create.'],
                      ['filename', 'f', None, 'Filename of the key file.'],
                      ['type', 't', None, 'Specify type of key to create.'],
                      ['comment', 'C', None, 'Provide new comment.'],
@@ -43,7 +57,7 @@ class GeneralOptions(usage.Options):
                 ['showpub', 'y', 'Read private key file and print public key.']]
 
     compData = usage.Completions(
-        optActions={"type": usage.CompleteList(["rsa", "dsa"])})
+        optActions={"type": usage.CompleteList(list(supportedKeyTypes.keys()))})
 
 
 
@@ -58,12 +72,13 @@ def run():
     log.discardLogs()
     log.deferr = handleError # HACK
     if options['type']:
-        if options['type'] == 'rsa':
-            generateRSAkey(options)
-        elif options['type'] == 'dsa':
-            generateDSAkey(options)
+        if options['type'].lower() in supportedKeyTypes:
+            print('Generating public/private %s key pair.' % (options['type']))
+            supportedKeyTypes[options['type'].lower()](options)
         else:
-            sys.exit('Key type was %s, must be one of: rsa, dsa' % options['type'])
+            sys.exit(
+                'Key type was %s, must be one of %s'
+                    % (options['type'], ', '.join(supportedKeyTypes.keys())))
     elif options['fingerprint']:
         printFingerprint(options)
     elif options['changepass']:
@@ -95,12 +110,13 @@ def handleError():
     raise
 
 
-
+ at _keyGenerator('rsa')
 def generateRSAkey(options):
     from cryptography.hazmat.backends import default_backend
     from cryptography.hazmat.primitives.asymmetric import rsa
 
-    print('Generating public/private rsa key pair.')
+    if not options['bits']:
+        options['bits'] = 1024
     keyPrimitive = rsa.generate_private_key(
         key_size=int(options['bits']),
         public_exponent=65537,
@@ -111,14 +127,35 @@ def generateRSAkey(options):
 
 
 
+ at _keyGenerator('dsa')
 def generateDSAkey(options):
     from cryptography.hazmat.backends import default_backend
     from cryptography.hazmat.primitives.asymmetric import dsa
 
-    print('Generating public/private dsa key pair.')
+    if not options['bits']:
+        options['bits'] = 1024
     keyPrimitive = dsa.generate_private_key(
         key_size=int(options['bits']),
-        backed=default_backend(),
+        backend=default_backend(),
+        )
+    key = keys.Key(keyPrimitive)
+    _saveKey(key, options)
+
+
+
+ at _keyGenerator('ecdsa')
+def generateECDSAkey(options):
+    from cryptography.hazmat.backends import default_backend
+    from cryptography.hazmat.primitives.asymmetric import ec
+
+    if not options['bits']:
+        options['bits'] = 256
+    # OpenSSH supports only nistp curves.
+    # See https://www.openssh.com/txt/release-5.7
+    curve  = b'nistp' + str(options['bits']).encode('ascii')
+    keyPrimitive = ec.generate_private_key(
+        curve=keys._curveTable[curve],
+        backend=default_backend()
         )
     key = keys.Key(keyPrimitive)
     _saveKey(key, options)
@@ -184,7 +221,7 @@ def changePassPhrase(options):
     except (keys.EncryptedKeyError, keys.BadKeyError) as e:
         sys.exit('Could not change passphrase: %s' % (e,))
 
-    with open(options['filename'], 'w') as fd:
+    with open(options['filename'], 'wb') as fd:
         fd.write(newkeydata)
 
     print('Your identification has been saved with the new passphrase.')
@@ -202,7 +239,10 @@ def displayPublicKey(options):
             options['pass'] = getpass.getpass('Enter passphrase: ')
         key = keys.Key.fromFile(
             options['filename'], passphrase = options['pass'])
-    print(key.public().toString('openssh'))
+    displayKey = key.public().toString('openssh')
+    if _PY3:
+        displayKey = displayKey.decode("ascii")
+    print(displayKey)
 
 
 
@@ -216,7 +256,8 @@ def _saveKey(key, options):
     @param options:
     @type options: L{dict}
     """
-    keyTypeName = key.type().lower()
+    KeyTypeMapping = {'EC': 'ecdsa', 'RSA': 'rsa', 'DSA': 'dsa'}
+    keyTypeName = KeyTypeMapping[key.type()]
     if not options['filename']:
         defaultPath = os.path.expanduser(u'~/.ssh/id_%s' % (keyTypeName,))
         newPath = raw_input(
diff --git a/src/twisted/conch/ssh/common.py b/src/twisted/conch/ssh/common.py
index 6fab155..a3cdf19 100644
--- a/src/twisted/conch/ssh/common.py
+++ b/src/twisted/conch/ssh/common.py
@@ -7,6 +7,7 @@ Common functions for the SSH classes.
 
 Maintainer: Paul Swartz
 """
+
 from __future__ import absolute_import, division
 
 import struct
@@ -14,7 +15,11 @@ import struct
 from twisted.conch.ssh._cryptography_backports import (
     intFromBytes as int_from_bytes, intToBytes as int_to_bytes)
 
-from twisted.python.compat import _PY3, long
+from twisted.python.deprecate import deprecated
+from twisted.python.versions import Version
+
+__all__ = ["NS", "getNS", "MP", "getMP", "ffs"]
+
 
 
 def NS(t):
@@ -87,56 +92,8 @@ def ffs(c, s):
 
 
 
-getMP_py = getMP
-MP_py = MP
-_MPpow_py = _MPpow
-pyPow = pow
-
-
-
-def _fastgetMP(data, count=1):
-    mp = []
-    c = 0
-    for i in range(count):
-        length = struct.unpack('!L', data[c:c + 4])[0]
-        mp.append(long(
-            gmpy.mpz(data[c + 4:c + 4 + length][::-1] + b'\x00', 256)))
-        c += length + 4
-    return tuple(mp) + (data[c:],)
-
-
-
-def _fastMP(i):
-    i2 = gmpy.mpz(i).binary()[::-1]
-    return struct.pack('!L', len(i2)) + i2
-
-
-
-def _fastMPpow(x, y, z=None):
-    r = pyPow(gmpy.mpz(x), y, z).binary()[::-1]
-    return struct.pack('!L', len(r)) + r
-
-
-
+ at deprecated(Version("Twisted", 16, 5, 0))
 def install():
-    global getMP, MP, _MPpow
-    getMP = _fastgetMP
-    MP = _fastMP
-    _MPpow = _fastMPpow
-    # XXX: We override builtin pow so that other code can benefit too.
-    # This is monkeypatching, and therefore VERY BAD.
-    def _fastpow(x, y, z=None, mpz=gmpy.mpz):
-        if type(x) in (long, int):
-            x = mpz(x)
-        return pyPow(x, y, z)
-    if _PY3:
-        __builtins__['pow'] = _fastpow
-    else:
-        import __builtin__
-        __builtin__.pow = _fastpow
-
-try:
-    import gmpy
-    install()
-except ImportError:
+    # This used to install gmpy, but is technically public API, so just do
+    # nothing.
     pass
diff --git a/src/twisted/conch/ssh/keys.py b/src/twisted/conch/ssh/keys.py
index 71b2f0b..cef4b87 100644
--- a/src/twisted/conch/ssh/keys.py
+++ b/src/twisted/conch/ssh/keys.py
@@ -3,7 +3,7 @@
 # See LICENSE for details.
 
 """
-Handling of RSA and DSA keys.
+Handling of RSA, DSA, and EC keys.
 """
 
 from __future__ import absolute_import, division
@@ -20,7 +20,10 @@ from incremental import Version
 from cryptography.exceptions import InvalidSignature
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import hashes, serialization
-from cryptography.hazmat.primitives.asymmetric import dsa, rsa, padding
+from cryptography.hazmat.primitives.asymmetric import dsa, rsa, padding, ec
+from cryptography.hazmat.primitives.serialization import (
+    load_pem_private_key, load_ssh_public_key)
+
 try:
     from cryptography.hazmat.primitives.asymmetric.utils import (
         encode_dss_signature, decode_dss_signature)
@@ -39,12 +42,45 @@ from twisted.conch.ssh import common, sexpy
 from twisted.conch.ssh.common import int_from_bytes, int_to_bytes
 from twisted.python import randbytes
 from twisted.python.compat import (
-    iterbytes, long, izip, nativeString, _PY3,
+    iterbytes, long, izip, nativeString, unicode, _PY3,
     _b64decodebytes as decodebytes, _b64encodebytes as encodebytes)
 from twisted.python.constants import NamedConstant, Names
 from twisted.python.deprecate import deprecated, getDeprecationWarningString
 
 
+_curveTable = {
+    b'nistp256' : ec.SECP256R1(),
+    b'nistp384' : ec.SECP384R1(),
+    b'nistp521' : ec.SECP521R1(),
+    b'nistk163' : ec.SECT163K1(),
+    b'nistp192' : ec.SECP192R1(),
+    b'nistp224' : ec.SECP224R1(),
+    b'nistk233' : ec.SECT233K1(),
+    b'nistb233' : ec.SECT233R1(),
+    b'nistk283' : ec.SECT283K1(),
+    b'nistk409' : ec.SECT409K1(),
+    b'nistb409' : ec.SECT409R1(),
+    b'nistt571' : ec.SECT571K1()
+    }
+
+
+_secToNist = {
+    b'secp256r1' : b'nistp256',
+    b'secp384r1' : b'nistp384',
+    b'secp521r1' : b'nistp521',
+    b'sect163k1' : b'nistk163',
+    b'secp192r1' : b'nistp192',
+    b'secp224r1' : b'nistp224',
+    b'sect233k1' : b'nistk233',
+    b'sect233r1' : b'nistb233',
+    b'sect283k1' : b'nistk283',
+    b'sect409k1' : b'nistk409',
+    b'sect409r1' : b'nistb409',
+    b'sect571k1' : b'nistt571'
+}
+
+
+
 
 
 class BadKeyError(Exception):
@@ -144,6 +180,10 @@ class Key(object):
         @rtype: L{Key}
         @return: The loaded key.
         """
+        if isinstance(data, unicode):
+            data = data.encode("utf-8")
+        if isinstance(passphrase, unicode):
+             passphrase = passphrase.encode("utf-8")
         if type is None:
             type = cls._guessStringType(data)
         if type is None:
@@ -175,6 +215,13 @@ class Key(object):
             integer g
             integer y
 
+        The format of ECDSA-SHA2-* public key blob is::
+            string 'ecdsa-sha2-[identifier]'
+            integer x
+            integer y
+
+            identifier is the standard NIST curve name.
+
         @type blob: L{bytes}
         @param blob: The key data.
 
@@ -199,6 +246,9 @@ class Key(object):
                     )
                 ).public_key(default_backend())
             )
+        elif keyType in [b'ecdsa-sha2-' + curve for curve in list(_curveTable.keys())]:
+            x, y, rest = common.getMP(rest, 2)
+            return cls._fromECComponents(x=x, y=y, curve=keyType)
         else:
             raise BadKeyError('unknown blob type: %s' % (keyType,))
 
@@ -226,6 +276,15 @@ class Key(object):
             integer y
             integer x
 
+        EC keys::
+            string 'ecdsa-sha2-[identifier]'
+            integer x
+            integer y
+            integer privateValue
+
+            identifier is the standard NIST curve name.
+
+
         @type blob: L{bytes}
         @param blob: The key data.
 
@@ -241,6 +300,10 @@ class Key(object):
         elif keyType == b'ssh-dss':
             p, q, g, y, x, rest = common.getMP(rest, 5)
             return cls._fromDSAComponents(y=y, g=g, p=p, q=q, x=x)
+        elif keyType in [b'ecdsa-sha2-' + curve for curve in list(_curveTable.keys())]:
+            x, y, privateValue, rest = common.getMP(rest, 3)
+            return cls._fromECComponents(x=x, y=y, curve=keyType,
+                privateValue=privateValue)
         else:
             raise BadKeyError('unknown blob type: %s' % (keyType,))
 
@@ -259,6 +322,10 @@ class Key(object):
         @rtype: L{twisted.conch.ssh.keys.Key}
         @raises BadKeyError: if the blob type is unknown.
         """
+        # ECDSA keys don't need base64 decoding which is required
+        # for RSA or DSA key.
+        if data.startswith(b'ecdsa-sha2'):
+            return cls(load_ssh_public_key(data, default_backend()))
         blob = decodebytes(data.split()[1])
         return cls._fromString_BLOB(blob)
 
@@ -283,6 +350,9 @@ class Key(object):
         The ASN.1 structure of a DSA key is::
             (0, p, q, g, y, x)
 
+        The ASN.1 structure of a ECDSA key is::
+            (ECParameters, OID, NULL)
+
         @type data: L{bytes}
         @param data: The key data.
 
@@ -299,7 +369,7 @@ class Key(object):
             * a passphrase is not provided for an encrypted key
         """
         lines = data.strip().split(b'\n')
-        kind = lines[0][11:14]
+        kind = lines[0][11:-17]
         if lines[1].startswith(b'Proc-Type: 4,ENCRYPTED'):
             if not passphrase:
                 raise EncryptedKeyError('Passphrase must be provided '
@@ -312,7 +382,7 @@ class Key(object):
             except ValueError:
                 raise BadKeyError('invalid DEK-info %r' % (lines[2],))
 
-            if cipher == b'AES-128-CBC':
+            if cipher in (b'AES-128-CBC', b'AES-256-CBC'):
                 algorithmClass = algorithms.AES
                 keySize = 16
                 if len(ivdata) != 32:
@@ -346,6 +416,11 @@ class Key(object):
             b64Data = b''.join(lines[1:-1])
             keyData = decodebytes(b64Data)
 
+        if kind == b'EC':
+            # ECDSA keys don't need base64 decoding which is required
+            # for RSA or DSA key.
+            return cls(load_pem_private_key(data, passphrase, default_backend()))
+
         try:
             decodedKey = berDecoder.decode(keyData)[0]
         except PyAsn1Error as e:
@@ -523,7 +598,7 @@ class Key(object):
         @type data: L{bytes}
         @param data: The key data.
         """
-        if data.startswith(b'ssh-'):
+        if data.startswith(b'ssh-') or data.startswith(b'ecdsa-sha2-'):
             return 'public_openssh'
         elif data.startswith(b'-----BEGIN'):
             return 'private_openssh'
@@ -531,7 +606,7 @@ class Key(object):
             return 'public_lsh'
         elif data.startswith(b'('):
             return 'private_lsh'
-        elif data.startswith(b'\x00\x00\x00\x07ssh-'):
+        elif data.startswith(b'\x00\x00\x00\x07ssh-') or data.startswith(b'\x00\x00\x00\x13ecdsa-'):
             ignored, rest = common.getNS(data)
             count = 0
             while rest:
@@ -625,6 +700,37 @@ class Key(object):
         return cls(keyObject)
 
 
+    @classmethod
+    def _fromECComponents(cls, x, y, curve, privateValue=None):
+        """
+        Build a key from EC components.
+
+        @param x: The affine x component of the public point used for verifying.
+        @type x: L{int}
+
+        @param y: The affine y component of the public point used for verifying.
+        @type y: L{int}
+
+        @param curve: NIST name of elliptic curve.
+        @type curve: L{bytes}
+
+        @param privateValue: The private value.
+        @type privateValue: L{int}
+        """
+
+        publicNumbers = ec.EllipticCurvePublicNumbers(
+            x=x, y=y, curve=_curveTable[curve.split(b'-')[2]])
+        if privateValue is None:
+            # We have public components.
+            keyObject = publicNumbers.public_key(default_backend())
+        else:
+            privateNumbers = ec.EllipticCurvePrivateNumbers(
+                private_value=privateValue, public_numbers=publicNumbers)
+            keyObject = privateNumbers.private_key(default_backend())
+
+        return cls(keyObject)
+
+
     def __init__(self, keyObject):
         """
         Initialize with a private or public
@@ -795,7 +901,8 @@ class Key(object):
         @return: C{True} if this is a public key.
         """
         return isinstance(
-            self._keyObject, (rsa.RSAPublicKey, dsa.DSAPublicKey))
+            self._keyObject,
+            (rsa.RSAPublicKey, dsa.DSAPublicKey, ec.EllipticCurvePublicKey))
 
 
     def public(self):
@@ -854,9 +961,10 @@ class Key(object):
     def type(self):
         """
         Return the type of the object we wrap.  Currently this can only be
-        'RSA' or 'DSA'.
+        'RSA', 'DSA', or 'EC'.
 
         @rtype: L{str}
+        @raises RuntimeError: If the object type is unknown.
         """
         if isinstance(
                 self._keyObject, (rsa.RSAPublicKey, rsa.RSAPrivateKey)):
@@ -864,21 +972,30 @@ class Key(object):
         elif isinstance(
                 self._keyObject, (dsa.DSAPublicKey, dsa.DSAPrivateKey)):
             return 'DSA'
+        elif isinstance(
+                self._keyObject, (ec.EllipticCurvePublicKey, ec.EllipticCurvePrivateKey)):
+            return 'EC'
         else:
             raise RuntimeError(
                 'unknown type of object: %r' % (self._keyObject,))
 
 
+
     def sshType(self):
         """
         Get the type of the object we wrap as defined in the SSH protocol,
-        defined in RFC 4253, Section 6.6. Currently this can only be b'ssh-rsa'
-        or b'ssh-dss'.
+        defined in RFC 4253, Section 6.6. Currently this can only be b'ssh-rsa',
+        b'ssh-dss' or b'ecdsa-sha2-[identifier]'.
+
+        identifier is the standard NIST curve name
 
         @return: The key type format.
         @rtype: L{bytes}
         """
-        return {'RSA': b'ssh-rsa', 'DSA': b'ssh-dss'}[self.type()]
+        if self.type() == 'EC':
+            return b'ecdsa-sha2-' + _secToNist[self._keyObject.curve.name.encode('ascii')]
+        else:
+            return {'RSA': b'ssh-rsa', 'DSA': b'ssh-dss'}[self.type()]
 
 
     def size(self):
@@ -890,6 +1007,8 @@ class Key(object):
         """
         if self._keyObject is None:
             return 0
+        elif self.type() == 'EC':
+            return self._keyObject.curve.key_size
         return self._keyObject.key_size
 
 
@@ -933,6 +1052,21 @@ class Key(object):
                 "p": numbers.public_numbers.parameter_numbers.p,
                 "q": numbers.public_numbers.parameter_numbers.q,
             }
+        elif isinstance(self._keyObject, ec.EllipticCurvePublicKey):
+            numbers = self._keyObject.public_numbers()
+            return{
+                "x": numbers.x,
+                "y": numbers.y,
+                "curve": self.sshType(),
+            }
+        elif isinstance(self._keyObject, ec.EllipticCurvePrivateKey):
+            numbers = self._keyObject.private_numbers()
+            return {
+                "x": numbers.public_numbers.x,
+                "y": numbers.public_numbers.y,
+                "privateValue": numbers.private_value,
+                "curve": self.sshType(),
+            }
         else:
             raise RuntimeError("Unexpected key type: %s" % (self._keyObject,))
... 12536 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/twisted.git



More information about the Python-modules-commits mailing list