Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#8966] Adding curve25519 and ed25519 #644

Open
wants to merge 105 commits into
base: trunk
from

Conversation

Projects
None yet
8 participants
@the0id
Copy link
Contributor

commented Dec 23, 2016

This adds curve25519 and ed25519 to Twisted. Cryptography doesn't support 25519 yet, so pyNaCL is required.

the0id and others added some commits Jul 27, 2016

Adding in ECDH, ECDSA, and Curve25519 to Conch.
Curve25519 is not supported by Cryptography, so pynacl and curve25519-donna are required.
This has the same ECDSA issue as the other branch does that it is mostly, but not completely stable.
@the0id

This comment has been minimized.

Copy link
Contributor Author

commented Apr 11, 2017

@glyph I see what you're saying now. No problem, can do, as soon as I figure out how to do. :)

@the0id

This comment has been minimized.

Copy link
Contributor Author

commented Apr 18, 2017

I can't tell if I did this right. The new tests ran but codecov didn't.

@glyph

This comment has been minimized.

Copy link
Member

commented Apr 19, 2017

Codecov has the occasional reliability issue :-\

the0id added some commits Apr 19, 2017

@the0id

This comment has been minimized.

Copy link
Contributor Author

commented Apr 20, 2017

I got 99 commits, so lets merge this one.

@@ -126,6 +127,25 @@ class _DHGroupExchangeSHA1(object):


@implementer(_IFixedGroupKexAlgorithm)
class _DHGroup1SHA1(object):

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

This still needs to be removed.

@@ -3,7 +3,7 @@
# See LICENSE for details.

"""
Handling of RSA, DSA, and EC keys.
Handling of RSA, DSA, EC, and *25519 keys.

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

This should just say Ed25519, this module doesn't do anything with X25519

@@ -289,6 +304,9 @@ def _fromString_PRIVATE_BLOB(cls, blob):
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 == b'ssh-ed25519':
pr = nacl.signing.SigningKey(common.getNS(rest)[0])

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

The variable name pr has me a bit confused; can we pick something more intuitive?

@@ -589,7 +617,10 @@ def _guessStringType(cls, data):
return 'public_lsh'
elif data.startswith(b'('):
return 'private_lsh'
elif data.startswith(b'\x00\x00\x00\x07ssh-') or data.startswith(b'\x00\x00\x00\x13ecdsa-'):
elif data.startswith(b'\x00\x00\x00\x0bssh-'): # ED25519

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

The data will continue ssh-ed25519 right? Might be easier to read if you include that in the string.

This comment has been minimized.

Copy link
@the0id

the0id May 31, 2017

Author Contributor

It will, and I see what you're saying, but I think it's better how it is. It's a little faster to process and it fits the convention of the rest of the checks. :)

@@ -786,7 +841,8 @@ def __repr__(self):
o = o[:-1]
lines.append('\t' + o)
lines[-1] = lines[-1] + '>'
return '\n'.join(lines)
reprstr = '\n'.join(lines)
return reprstr

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

These changes appear to be unrelated, there's nothing wrong with just return when you have the value.

This comment has been minimized.

Copy link
@the0id

the0id May 31, 2017

Author Contributor

Moving the return where it is now fits in better with the block. Each conditional creates a reprstr value, with a single return of that value at the end.

@@ -901,7 +958,10 @@ def public(self):
@rtype: L{Key}
@return: A public key.
"""
return Key(self._keyObject.public_key())
if self.type() is 'ED25519':

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

This should not use is, it should use ==

This comment has been minimized.

Copy link
@the0id

the0id May 31, 2017

Author Contributor

Good catch. 👍

elif isinstance(
self._keyObject, (nacl.signing.VerifyKey,
nacl.signing.SigningKey)):
return 'ED25519'

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

Conventionally, it's typed Ed25519, lowercase d.

This comment has been minimized.

Copy link
@the0id

the0id May 31, 2017

Author Contributor

I think it's better to leave this all caps because the rest of the return strings are in all caps.


if self.type() == 'EC':
if self.type() == 'ED25519':
# OpenSSH loosely follows the openssh-key-v1 specification

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

This logic should be split out into its own method for readability.

try:
key.verify(data, common.getNS(signature)[0])
return True
except:

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

Catch a specific exception, not a bare catch.

@@ -1578,8 +1602,17 @@ def ssh_KEXINIT(self, packet):
# Connection was disconnected while doing base processing.
# Maybe no common protocols were agreed.
return
# Curve25519
if self.kexAlg.find(b'curve25519') >= 0:

This comment has been minimized.

Copy link
@alex

alex May 27, 2017

Contributor

This can just be b'curve25519' in self.kexAlg

@alex

This comment has been minimized.

Copy link
Contributor

commented May 27, 2017

There's also a merge conflict.

@rodrigc

This comment has been minimized.

Copy link
Contributor

commented May 27, 2017

You need to take a merge from trunk and move your 8966.feature file to the newsfragments directory. Things have moved around due to this: #763

@the0id

This comment has been minimized.

Copy link
Contributor Author

commented May 31, 2017

@alex, @rodrigc thanks for the review. I've made some of the changes requested, and gave my reasons for not changing the others.

@rodrigc thanks for the head's up about moving the file to newsfragments. @markrwilliams helped me out with the same thing on another PR. :)

@the0id

This comment has been minimized.

Copy link
Contributor Author

commented Aug 22, 2017

The last two times appveyor has run two of the tests fail because openssh can't be installed.

Build started
git clone -q https://github.com/twisted/twisted.git C:\projects\twisted
git fetch -q origin +refs/pull/644/merge:
git checkout -qf FETCH_HEAD
Restoring build cache
Cache 'C:\Users\appveyor\AppData\Local\pip\Cache' - Restored
Running Install scripts
choco install openssh -confirm
Chocolatey v0.10.7
Installing the following packages:
openssh
By installing you accept licenses for the packages.
Progress: Downloading openssh 0.0.18.0... 45%openssh not installed. An error occurred during installation:
 The operation has timed out.
openssh package files install completed. Performing other installation steps.
The install of openssh was NOT successful.
openssh not installed. An error occurred during installation:
 The operation has timed out.
Chocolatey installed 0/1 packages. 1 packages failed.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
Failures
 - openssh (exited 1) - openssh not installed. An error occurred during installation:
 The operation has timed out.
Command exited with code 1
@rodrigc

This comment has been minimized.

@the0id

This comment has been minimized.

Copy link
Contributor Author

commented Aug 22, 2017

@rodrigc Thanks, I missed that message.

the0id added some commits Aug 24, 2017

@markrwilliams

This comment has been minimized.

Copy link
Member

commented Mar 23, 2018

@the0id You put a lot of effort into this PR - thanks for that!

However, given that I'm writing from a future where cryptography supports curve25519, I think this PR should be closed and a new one opened that uses cryptography instead of pynacl. That would eliminate the need to call into a private API.

# One file can have multiple keys.
# For now just grab the last private key.
privKey = common.getNS(
keyData[keyData.rindex(b'25519') + 5:], 2)[1][:32]

This comment has been minimized.

Copy link
@cjwatson

cjwatson Aug 30, 2018

This isn't very accurate parsing; it should parse the documented private key protocol properly.

I've just opened #1053 to support the new private key format. Assuming that lands, I think this PR should be reworked on top of that, since it will then just need to introduce a new key type rather than also introducing a new format.

@cjwatson

This comment has been minimized.

Copy link

commented Oct 5, 2018

However, given that I'm writing from a future where cryptography supports curve25519, I think this PR should be closed and a new one opened that uses cryptography instead of pynacl. That would eliminate the need to call into a private API.

So, um. Current cryptography supports x25519, but it doesn't in fact support ed25519. There's some work in progress for that. I tried rewriting this PR on top of that branch and #1053, but I quickly ran into ed25519.Ed25519PublicKey.from_public_bytes apparently not working properly, so I'm stalled on that for now until I get feedback from the author of that cryptography branch.

Even aside from that, though, this as-yet-unlanded cryptography support requires OpenSSL >= 1.1.1, and that's going to be quite a pain for me to deploy in the environments where I need to use this Conch Ed25519 support. Given that it isn't in Ubuntu 18.04, realistically it means I'm likely to be stuck with complicated and maintenance-intensive backports until at least 2020; I'd really prefer to be running OpenSSL libraries that our security team is maintaining, so I don't want to have to maintain an OpenSSL backport if I can possibly avoid it, and nor do I want to use statically-linked wheels.

I'm certainly not arguing with cryptography being the right approach long-term. But particularly given the likely OpenSSL deployment issues, could we perhaps revisit sticking with pynacl for now? It wouldn't need to be permanent.

@cjwatson

This comment has been minimized.

Copy link

commented Oct 6, 2018

I'm certainly not arguing with cryptography being the right approach long-term. But particularly given the likely OpenSSL deployment issues, could we perhaps revisit sticking with pynacl for now? It wouldn't need to be permanent.

Refinement: we could bring up this support with cryptography once the support there has landed, but then also add support for using pynacl as an alternative; I think this would basically just be a matter of providing shim versions of Ed25519PublicKey and Ed25519PrivateKey. That way, we'd have mostly modern code, and when the time comes that we can reasonably assume OpenSSL 1.1.1 everywhere it'll be easy to drop the pynacl-based shims.

@glyph

This comment has been minimized.

Copy link
Member

commented Oct 15, 2018

Refinement: we could bring up this support with cryptography once the support there has landed, but then also add support for using pynacl as an alternative; I think this would basically just be a matter of providing shim versions of Ed25519PublicKey and Ed25519PrivateKey. That way, we'd have mostly modern code, and when the time comes that we can reasonably assume OpenSSL 1.1.1 everywhere it'll be easy to drop the pynacl-based shims.

This sounds great - are you planning to proceed with this strategy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.