[Twisted-Python] Possible bug on twisted.conch.ssh.keys?
![](https://secure.gravatar.com/avatar/68599b3b210ee81b094256921722ecc6.jpg?s=120&d=mm&r=g)
Hello folks, I'm facing a problem here while trying to implement a ssh server and client using twisted. There are some deprecated functions that are pointing me to use new ones, which in turn doesn't seem to work fine. I'm not sure if it is the case, mainly because the deprecated functions are calling the new ones, but while debuging the code I found that something there is wrong, and that can potentially be hapenning because of the changes recently made to that module. As I'm somehow new to twisted I'm not sure about my statements arround the problem. Here follows the codes and exceptions I'm getting: <client_code> #!/usr/bin/env python # This code was based on an example from twisted website from twisted.conch.ssh import transport, userauth, connection from twisted.conch.ssh import common, keys, channel from twisted.internet import defer, protocol, reactor from twisted.python import log import struct, sys, getpass, os USER = 'ssh' HOST = 'localhost' PORT = 2222 PUBKEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQD3n4sYqbdnlVyvy2SRUmQ5HJg2NDHyC0m4FIykDygXW2PTcSHU/Jany95D54qAEkUra0KHk94KvyGhNVYXqPmzPLu4onlr0Y/gQzEsIy15jDGjMWVCX/8+PQJxMYObSKs8U1o/h5fDNeKQs4bZbrm+35eT/Kvyerqa6ab5OsIEnQ==" PRIVKEY = """-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQD3n4sYqbdnlVyvy2SRUmQ5HJg2NDHyC0m4FIykDygXW2PTcSHU /Jany95D54qAEkUra0KHk94KvyGhNVYXqPmzPLu4onlr0Y/gQzEsIy15jDGjMWVC X/8+PQJxMYObSKs8U1o/h5fDNeKQs4bZbrm+35eT/Kvyerqa6ab5OsIEnQIDAQAB AoGAK2MWASVDkG+4RMkTfu77xpH/DYhJtApMSWe4WMqbELSfoh2xetsjHpV3BVjd iKEq43ewuYasIh/pKZDp281sqqXdg9VI9ZW7kB00FhO2wA4emCIVj6CHMl1K9NrU 9Spy40garaYnDdud79SnKtxlKQEALOwCpTEcrjGOLBTbirUCQQD/FkP1zhpOSaOy B32CiC13W5fFfREzBxzQ3Med1i1OYtFfBEdJqv/Z7APadNN8ySI3r+UAfGatTzJI zbiSZ2fHAkEA+IJwWpw6d8R3t7+8UgTrqdsZhLRdidO0cHcIFcnU/QYZg+iw3F+q Tuz/mngpfb5214r8zwcwlNzsC4+fyOOYewJBAMPstRw6Rog1FW8rQ6Kbt9hCWItO aYR5BRADU6sOk1PuoIPLhHm3xrX6CmejbcEdt5NwHYNHCZI6DxRONmL024cCQBky eJvnXVJJfG4IJdsXHqIBUiwPcbCI47HHj+1NoqfpF2s1i8E8ffM0upH5/xL93eTq 9ck0DGv7nn9pl6Tx1sMCQCWZbWDnmEdsSoNUQZ8fyQEDoZ/2gUP+R2/WpLikwmSA 41n7cUONVthIYOZw0qQPP//PyPtMVxcYT76D5QACEK8= -----END RSA PRIVATE KEY-----""" class ClientTransport(transport.SSHClientTransport): def connectionMade(self): transport.SSHClientTransport.connectionMade(self) def verifyHostKey(self, hostKey, fingerprint): return defer.succeed(1) def connectionSecure(self): self.requestService(ClientUserAuth(USER, ClientConnection())) class ClientUserAuth(userauth.SSHUserAuthClient): def getPublicKey(self): # Issue 1 return PUBKEY.encode("ascii") def getPrivateKey(self): # Issue 2 return defer.succeed(keys.getPrivateKeyObject(data=PRIVKEY)) def getPassword(self): return defer.succeed(getpass.getpass("%s@%s's password: " % (USER, HOST))) def getGenericAnswers(self, name, instruction, questions): import pdb; pdb.set_trace() log.debug("Get Generic answers: %s, %s, %s" % (name, instruction, questions)) answers = [] for prompt, echo in questions: if echo: answer = raw_input(prompt) else: answer = getpass.getpass(prompt) answers.append(answer) return defer.succeed(answers) def tryAuth(self, kind): kind = "publickey" log.debug("tryAuth: %s" % kind) log.debug("Public Key: %s" % self.getPublicKey()) return userauth.SSHUserAuthClient.tryAuth(self, kind) def signData(self, publicKey, signData): log.debug("Ran signData with %s and %s" % (publicKey, signData)) import pdb; pdb.set_trace() signed = userauth.SSHUserAuthClient.signData(self, publicKey, signData) return signed def auth_publickey(self): log.debug("Trying Auth Method: Public Key") return userauth.SSHUserAuthClient.auth_publickey(self) class ClientConnection(connection.SSHConnection): def serviceStarted(self): log.debug("Service started") self.openChannel(TrueChannel(2**16, 2**15, self)) self.openChannel(FalseChannel(2**16, 2**15, self)) self.openChannel(CatChannel(2**16, 2**15, self)) class TrueChannel(channel.SSHChannel): name = 'session' def openFailed(self, reason): print 'true failed', reason def channelOpen(self, ignoredData): self.conn.sendRequest(self, 'exec', common.NS('true')) def request_exit_status(self, data): status = struct.unpack('>L', data)[0] print 'true status was: %s' % status self.loseConnection() class FalseChannel(channel.SSHChannel): name = 'session' def openFailed(self, reason): print 'false failed', reason def channelOpen(self, ignoredData): self.conn.sendRequest(self, 'exec', common.NS('false')) def request_exit_status(self, data): status = struct.unpack('>L', data)[0] print 'false status was: %s' % status self.loseConnection() class CatChannel(channel.SSHChannel): name = 'session' def openFailed(self, reason): print 'echo failed', reason def channelOpen(self, ignoredData): self.data = '' d = self.conn.sendRequest(self, 'exec', common.NS('cat'), wantReply = 1) d.addCallback(self._cbRequest) def _cbRequest(self, ignored): self.write('hello conch\n') self.conn.sendEOF(self) def dataReceived(self, data): self.data += data def closed(self): print 'got data from cat: %s' % repr(self.data) self.loseConnection() reactor.stop() protocol.ClientCreator(reactor, ClientTransport).connectTCP(HOST, 2222) reactor.run() </client_code> The issues: 1 - I had to encode the public key to ascii prior to using it. I don't know why, but the struct was raising an exception telling that one of the chars where out of the ascii range. But it doesn't look to have any character outside the ascii range, AFAIK. Anyway, it worked when I did the conversion to ascii. 2 - When I use: keys.Key.fromString(data=PRIVKEY) instead of the deprecated keys.getPrivateKeyObject(data=PRIVKEY), I get this error while trying to authenticate: <error> # This was caught directly from pdb prompt: p:\n\t00:f8:82:70:5a:9c:3a:77:c4:77:b7:bf:bc:52:04:\n\teb:a9:db:19:84:b4:5d:89:d3:b4:70:77:08:15:c9:\n\td4:fd:06:19:83:e8:b0:dc:5f:aa:4e:ec:ff:9a:78:\n\t29:7d:be:76:d7:8a:fc:cf:07:30:94:dc:ec:0b:8f:\n\t9f:c8:e3:98:7b\nattr u:\n\t25:99:6d:60:e7:98:47:6c:4a:83:54:41:9f:1f:c9:\n\t01:03:a1:9f:f6:81:43:fe:47:6f:d6:a4:b8:a4:c2:\n\t64:80:e3:59:fb:71:43:8d:56:d8:48:60:e6:70:d2:\n\ta4:0f:3f:ff:cf:c8:fb:4c:57:17:18:4f:be:83:e5:\n\t00:02:10:af>' </error> This is the function that raised that exception: http://twistedmatrix.com/trac/browser/tags/releases/twisted-8.1.0/twisted/co... It looks like the problem is that the class name doesn't start with Crypto.PublicKey. Then, when I use the deprecated method, this is what I have: <not_an_error>
After moving to the deprecated method, everything seems to work ok with the client, but then I started to have a similar problem at the server side, while verifying client's signature. Here is the relevant part of the server code, which is the method requestAvatarId of the Credential Checker I implemented: <server_code> # This code is based in an example that I caught from twisted website class PublicKeyChecker(): implements(checkers.ICredentialsChecker) credentialInterfaces = (credentials.ISSHPrivateKey, ) def requestAvatarId(self, credentials): # I removed here the code that verified if the user is registered in our database, to easy for you guys to understand the relevant part of the code. Just consider that the variable user contains the found user object. user_key = user.key.public_key if not credentials.blob == user_key: raise failure.Failure(error.ConchError("Wrong key.")) if not credentials.signature: return failure.Failure(error.ValidPublicKey()) pub_key = Key.fromString(data=credentials.blob) # Issue 3 if verifySignature(pub_key, credentials.signature, credentials.sigData): return credentials.username else: return failure.Failure(error.ConchError("Incorrect Signature.")) else: return failure.Failure(error.ConchError("Authentication Failed.")) </server_code> 3 - Then, while I get to the verifySignature method, I get the following error: <error> RuntimeError: unknown type of object: <RSA Public Key (1023 bits) attr e: 01:00:01 attr n: 00:f7:9f:8b:18:a9:b7:67:95:5c:af:cb:64:91:52: 64:39:1c:98:36:34:31:f2:0b:49:b8:14:8c:a4:0f: 28:17:5b:63:d3:71:21:d4:fc:96:a7:cb:de:43:e7: 8a:80:12:45:2b:6b:42:87:93:de:0a:bf:21:a1:35: 56:17:a8:f9:b3:3c:bb:b8:a2:79:6b:d1:8f:e0:43: 31:2c:23:2d:79:8c:31:a3:31:65:42:5f:ff:3e:3d:... </error> Which is the same exception raised by the key.type() function that have put us at the same trouble in the client. Then, at the debuger, I found that the correct key (which is a class with name starting with Crypto.PublicKey) is right inside this "unknown" object, which is a RSA Public Key in object.keyObject.keyObject! I ran the WingIDE debugger and simply saw that, as you can see in this screenshot: http://www.imageno.com/z99azx3v7qnzpic.html Ok, I also get the deprecated warning while using the verifySignature method instead of Key(obj).verify(sig, data), then I decided to test it also just to don't make you guys wast your time with me for nothing. I called pub_key.verify(credentials.signature, credentials.sigData) instead of that verifySignature call, and it returned False instead leading to a failure in authentication. Both apps (client and server) are running inside the same machine, consulting the same database, the same keys and user, so there it is not reasonable to be failing if my code is correct. Maybe I missed something. Can you guys help me? Sorry about the very long email, but I tried to be as much verbose as I could in order to help you guys help me. Kind Regards, -- Adriano Monteiro Marques http://adriano-marques.blogspot.com http://umit.sourceforge.net py.adriano@gmail.com "Don't stay in bed, unless you can make money in bed." - George Burns
![](https://secure.gravatar.com/avatar/68599b3b210ee81b094256921722ecc6.jpg?s=120&d=mm&r=g)
Folks, While I was trying to find why the verify method was returning False, I discovered that inside the _verify method, at RSA.py, there was the following code: <RSA_code> def _verify(self, M, sig): m2=self._encrypt(sig[0]) if m2[0]==M: return 1 else: return 0 </RSA_code> Using the live debug of wingide, I checked the values, and here is the result: <debug>
So, m2[0] is really different from M, but why if I'm using the same keys from the same place? Hope this helps to clear the issue. Kind Regards, On Mon, Jul 28, 2008 at 10:29 AM, Adriano Marques <py.adriano@gmail.com> wrote:
-- Adriano Monteiro Marques http://adriano-marques.blogspot.com http://umit.sourceforge.net py.adriano@gmail.com "Don't stay in bed, unless you can make money in bed." - George Burns
![](https://secure.gravatar.com/avatar/b3407ff6ccd34c6e7c7a9fdcfba67a45.jpg?s=120&d=mm&r=g)
Adriano Marques wrote: [...]
Suspiciously, they only differ in the last 50 or so decimal digits. That suggests a bug in the way they are being read, maybe? As to your problems using un-deprecated APIs, a wild guess is that maybe your PyCrypto version is too old? -Andrew.
![](https://secure.gravatar.com/avatar/68599b3b210ee81b094256921722ecc6.jpg?s=120&d=mm&r=g)
Hi Andrew, On Mon, Jul 28, 2008 at 9:00 PM, Andrew Bennetts <andrew-twisted@puzzling.org> wrote:
Thanks for your response! Yes, I thought it was very strange that they only differed in the last digits. It took me a while to figure that out, mainly because in the debuger I couldn't see that last digits properly. Well, maybe the way I'm storing the keys? Is this the correct format? <keys> PUBKEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQD3n4sYqbdnlVyvy2SRUmQ5HJg2NDHyC0m4FIykDygXW2PTcSHU/Jany95D54qAEkUra0KHk94KvyGhNVYXqPmzPLu4onlr0Y/gQzEsIy15jDGjMWVCX/8+PQJxMYObSKs8U1o/h5fDNeKQs4bZbrm+35eT/Kvyerqa6ab5OsIEnQ==" PRIVKEY = """-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQD3n4sYqbdnlVyvy2SRUmQ5HJg2NDHyC0m4FIykDygXW2PTcSHU /Jany95D54qAEkUra0KHk94KvyGhNVYXqPmzPLu4onlr0Y/gQzEsIy15jDGjMWVC X/8+PQJxMYObSKs8U1o/h5fDNeKQs4bZbrm+35eT/Kvyerqa6ab5OsIEnQIDAQAB AoGAK2MWASVDkG+4RMkTfu77xpH/DYhJtApMSWe4WMqbELSfoh2xetsjHpV3BVjd iKEq43ewuYasIh/pKZDp281sqqXdg9VI9ZW7kB00FhO2wA4emCIVj6CHMl1K9NrU 9Spy40garaYnDdud79SnKtxlKQEALOwCpTEcrjGOLBTbirUCQQD/FkP1zhpOSaOy B32CiC13W5fFfREzBxzQ3Med1i1OYtFfBEdJqv/Z7APadNN8ySI3r+UAfGatTzJI zbiSZ2fHAkEA+IJwWpw6d8R3t7+8UgTrqdsZhLRdidO0cHcIFcnU/QYZg+iw3F+q Tuz/mngpfb5214r8zwcwlNzsC4+fyOOYewJBAMPstRw6Rog1FW8rQ6Kbt9hCWItO aYR5BRADU6sOk1PuoIPLhHm3xrX6CmejbcEdt5NwHYNHCZI6DxRONmL024cCQBky eJvnXVJJfG4IJdsXHqIBUiwPcbCI47HHj+1NoqfpF2s1i8E8ffM0upH5/xL93eTq 9ck0DGv7nn9pl6Tx1sMCQCWZbWDnmEdsSoNUQZ8fyQEDoZ/2gUP+R2/WpLikwmSA 41n7cUONVthIYOZw0qQPP//PyPtMVxcYT76D5QACEK8= -----END RSA PRIVATE KEY-----""" </keys> I was researching the matter, and then I saw in the Twisted book that I should use base64.decode in order to compare the key with the credential.blob, but when I do that the key doesn't look the same when compared to the blob and the authentication fails. So, maybe I may be sending the key the wrong way, but I don't have a clue of what is the right way.
As to your problems using un-deprecated APIs, a wild guess is that maybe your PyCrypto version is too old?
I think it is not the case. I have the latest one:
Crypto.__version__ '2.0.1'
I'm running on a Mac OS X Leopard, if that may help you to help me ;-) Thanks for the help! Kind Regards, -- Adriano Monteiro Marques http://adriano-marques.blogspot.com http://umit.sourceforge.net py.adriano@gmail.com "Don't stay in bed, unless you can make money in bed." - George Burns
![](https://secure.gravatar.com/avatar/68599b3b210ee81b094256921722ecc6.jpg?s=120&d=mm&r=g)
Folks, While I was trying to find why the verify method was returning False, I discovered that inside the _verify method, at RSA.py, there was the following code: <RSA_code> def _verify(self, M, sig): m2=self._encrypt(sig[0]) if m2[0]==M: return 1 else: return 0 </RSA_code> Using the live debug of wingide, I checked the values, and here is the result: <debug>
So, m2[0] is really different from M, but why if I'm using the same keys from the same place? Hope this helps to clear the issue. Kind Regards, On Mon, Jul 28, 2008 at 10:29 AM, Adriano Marques <py.adriano@gmail.com> wrote:
-- Adriano Monteiro Marques http://adriano-marques.blogspot.com http://umit.sourceforge.net py.adriano@gmail.com "Don't stay in bed, unless you can make money in bed." - George Burns
![](https://secure.gravatar.com/avatar/b3407ff6ccd34c6e7c7a9fdcfba67a45.jpg?s=120&d=mm&r=g)
Adriano Marques wrote: [...]
Suspiciously, they only differ in the last 50 or so decimal digits. That suggests a bug in the way they are being read, maybe? As to your problems using un-deprecated APIs, a wild guess is that maybe your PyCrypto version is too old? -Andrew.
![](https://secure.gravatar.com/avatar/68599b3b210ee81b094256921722ecc6.jpg?s=120&d=mm&r=g)
Hi Andrew, On Mon, Jul 28, 2008 at 9:00 PM, Andrew Bennetts <andrew-twisted@puzzling.org> wrote:
Thanks for your response! Yes, I thought it was very strange that they only differed in the last digits. It took me a while to figure that out, mainly because in the debuger I couldn't see that last digits properly. Well, maybe the way I'm storing the keys? Is this the correct format? <keys> PUBKEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQD3n4sYqbdnlVyvy2SRUmQ5HJg2NDHyC0m4FIykDygXW2PTcSHU/Jany95D54qAEkUra0KHk94KvyGhNVYXqPmzPLu4onlr0Y/gQzEsIy15jDGjMWVCX/8+PQJxMYObSKs8U1o/h5fDNeKQs4bZbrm+35eT/Kvyerqa6ab5OsIEnQ==" PRIVKEY = """-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQD3n4sYqbdnlVyvy2SRUmQ5HJg2NDHyC0m4FIykDygXW2PTcSHU /Jany95D54qAEkUra0KHk94KvyGhNVYXqPmzPLu4onlr0Y/gQzEsIy15jDGjMWVC X/8+PQJxMYObSKs8U1o/h5fDNeKQs4bZbrm+35eT/Kvyerqa6ab5OsIEnQIDAQAB AoGAK2MWASVDkG+4RMkTfu77xpH/DYhJtApMSWe4WMqbELSfoh2xetsjHpV3BVjd iKEq43ewuYasIh/pKZDp281sqqXdg9VI9ZW7kB00FhO2wA4emCIVj6CHMl1K9NrU 9Spy40garaYnDdud79SnKtxlKQEALOwCpTEcrjGOLBTbirUCQQD/FkP1zhpOSaOy B32CiC13W5fFfREzBxzQ3Med1i1OYtFfBEdJqv/Z7APadNN8ySI3r+UAfGatTzJI zbiSZ2fHAkEA+IJwWpw6d8R3t7+8UgTrqdsZhLRdidO0cHcIFcnU/QYZg+iw3F+q Tuz/mngpfb5214r8zwcwlNzsC4+fyOOYewJBAMPstRw6Rog1FW8rQ6Kbt9hCWItO aYR5BRADU6sOk1PuoIPLhHm3xrX6CmejbcEdt5NwHYNHCZI6DxRONmL024cCQBky eJvnXVJJfG4IJdsXHqIBUiwPcbCI47HHj+1NoqfpF2s1i8E8ffM0upH5/xL93eTq 9ck0DGv7nn9pl6Tx1sMCQCWZbWDnmEdsSoNUQZ8fyQEDoZ/2gUP+R2/WpLikwmSA 41n7cUONVthIYOZw0qQPP//PyPtMVxcYT76D5QACEK8= -----END RSA PRIVATE KEY-----""" </keys> I was researching the matter, and then I saw in the Twisted book that I should use base64.decode in order to compare the key with the credential.blob, but when I do that the key doesn't look the same when compared to the blob and the authentication fails. So, maybe I may be sending the key the wrong way, but I don't have a clue of what is the right way.
As to your problems using un-deprecated APIs, a wild guess is that maybe your PyCrypto version is too old?
I think it is not the case. I have the latest one:
Crypto.__version__ '2.0.1'
I'm running on a Mac OS X Leopard, if that may help you to help me ;-) Thanks for the help! Kind Regards, -- Adriano Monteiro Marques http://adriano-marques.blogspot.com http://umit.sourceforge.net py.adriano@gmail.com "Don't stay in bed, unless you can make money in bed." - George Burns
participants (2)
-
Adriano Marques
-
Andrew Bennetts