[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