File: //lib/python3/dist-packages/twisted/conch/test/test_keys.py
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{twisted.conch.ssh.keys}.
"""
from __future__ import absolute_import, division
from twisted.python.reflect import requireModule
cryptography = requireModule("cryptography")
if cryptography is None:
skipCryptography = 'Cannot run without cryptography.'
pyasn1 = requireModule("pyasn1")
if cryptography and pyasn1:
from twisted.conch.ssh import keys, common, sexpy
import base64
import os
from twisted.conch.test import keydata
from twisted.python import randbytes
from twisted.trial import unittest
from twisted.python.compat import long
from twisted.python.filepath import FilePath
class KeyTests(unittest.TestCase):
if cryptography is None:
skip = skipCryptography
if pyasn1 is None:
skip = "Cannot run without PyASN1"
def setUp(self):
self.rsaObj = keys.Key._fromRSAComponents(
n=keydata.RSAData['n'],
e=keydata.RSAData['e'],
d=keydata.RSAData['d'],
p=keydata.RSAData['p'],
q=keydata.RSAData['q'],
u=keydata.RSAData['u'],
)._keyObject
self.dsaObj = keys.Key._fromDSAComponents(
y=keydata.DSAData['y'],
p=keydata.DSAData['p'],
q=keydata.DSAData['q'],
g=keydata.DSAData['g'],
x=keydata.DSAData['x'],
)._keyObject
self.ecObj = keys.Key._fromECComponents(
x=keydata.ECDatanistp256['x'],
y=keydata.ECDatanistp256['y'],
privateValue=keydata.ECDatanistp256['privateValue'],
curve=keydata.ECDatanistp256['curve']
)._keyObject
self.ecObj384 = keys.Key._fromECComponents(
x=keydata.ECDatanistp384['x'],
y=keydata.ECDatanistp384['y'],
privateValue=keydata.ECDatanistp384['privateValue'],
curve=keydata.ECDatanistp384['curve']
)._keyObject
self.ecObj521 = keys.Key._fromECComponents(
x=keydata.ECDatanistp521['x'],
y=keydata.ECDatanistp521['y'],
privateValue=keydata.ECDatanistp521['privateValue'],
curve=keydata.ECDatanistp521['curve']
)._keyObject
self.rsaSignature = (
b"\x00\x00\x00\x07ssh-rsa\x00\x00\x01\x00~Y\xa3\xd7\xfdW\xc6pu@"
b"\xd81\xa1S\xf3O\xdaE\xf4/\x1ex\x1d\xf1\x9a\xe1G3\xd9\xd6U\x1f"
b"\x8c\xd9\x1b\x8b\x90\x0e\x8a\xc1\x91\xd8\x0cd\xc9\x0c\xe7\xb2"
b"\xc9,'=\x15\x1cQg\xe7x\xb5j\xdbI\xc0\xde\xafb\xd7@\xcar\x0b"
b"\xce\xa3zM\x151q5\xde\xfa\x0c{wjKN\x88\xcbC\xe5\x89\xc3\xf9i"
b"\x96\x91\xdb\xca}\xdbR\x1a\x13T\xf9\x0cDJH\x0b\x06\xcfl\xf3"
b"\x13[\x82\xa2\x9d\x93\xfd\x8e\xce|\xfb^n\xd4\xed\xe2\xd1\x8a"
b"\xb7aY\x9bB\x8f\xa4\xc7\xbe7\xb5\x0b9j\xa4.\x87\x13\xf7\xf0"
b"\xda\xd7\xd2\xf9\x1f9p\xfd?\x18\x0f\xf2N\x9b\xcf/\x1e)\n>A\x19"
b"\xc2\xb5j\xf9UW\xd4\xae\x87B\xe6\x99t\xa2y\x90\x98\xa2\xaaf\xcb"
b"\x86\xe5k\xe3\xce\xe0u\x1c\xeb\x93\x1aN\x88\xc9\x93Y\xc3.V\xb1L"
b"44`C\xc7\xa66\xaf\xfa\x7f\x04Y\x92\xfa\xa4\x1a\x18%\x19\xd5 4^"
b"\xb9rY\xba \x01\xf9.\x89%H\xbe\x1c\x83A\x96"
)
self.dsaSignature = (
b'\x00\x00\x00\x07ssh-dss\x00\x00\x00(?\xc7\xeb\x86;\xd5TFA\xb4'
b'\xdf\x0c\xc4E@4,d\xbc\t\xd9\xae\xdd[\xed-\x82nQ\x8cf\x9b\xe8\xe1'
b'jrg\x84p<'
)
self.patch(randbytes, 'secureRandom', lambda x: b'\xff' * x)
self.keyFile = self.mktemp()
with open(self.keyFile, 'wb') as f:
f.write(keydata.privateRSA_lsh)
def tearDown(self):
os.unlink(self.keyFile)
def test_size(self):
"""
The L{keys.Key.size} method returns the size of key object in bits.
"""
self.assertEqual(keys.Key(self.rsaObj).size(), 2048)
self.assertEqual(keys.Key(self.dsaObj).size(), 1024)
self.assertEqual(keys.Key(self.ecObj).size(), 256)
self.assertEqual(keys.Key(self.ecObj384).size(), 384)
self.assertEqual(keys.Key(self.ecObj521).size(), 521)
def test__guessStringType(self):
"""
Test that the _guessStringType method guesses string types
correctly.
"""
self.assertEqual(keys.Key._guessStringType(keydata.publicRSA_openssh),
'public_openssh')
self.assertEqual(keys.Key._guessStringType(keydata.publicDSA_openssh),
'public_openssh')
self.assertEqual(keys.Key._guessStringType(keydata.publicECDSA_openssh),
'public_openssh')
self.assertEqual(keys.Key._guessStringType(
keydata.privateRSA_openssh), 'private_openssh')
self.assertEqual(keys.Key._guessStringType(
keydata.privateDSA_openssh), 'private_openssh')
self.assertEqual(keys.Key._guessStringType(
keydata.privateECDSA_openssh), 'private_openssh')
self.assertEqual(keys.Key._guessStringType(keydata.publicRSA_lsh),
'public_lsh')
self.assertEqual(keys.Key._guessStringType(keydata.publicDSA_lsh),
'public_lsh')
self.assertEqual(keys.Key._guessStringType(keydata.privateRSA_lsh),
'private_lsh')
self.assertEqual(keys.Key._guessStringType(keydata.privateDSA_lsh),
'private_lsh')
self.assertEqual(keys.Key._guessStringType(
keydata.privateRSA_agentv3), 'agentv3')
self.assertEqual(keys.Key._guessStringType(
keydata.privateDSA_agentv3), 'agentv3')
self.assertEqual(keys.Key._guessStringType(
b'\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x01'),
'blob')
self.assertEqual(keys.Key._guessStringType(
b'\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x01'),
'blob')
self.assertEqual(keys.Key._guessStringType(b'not a key'),
None)
def test_public(self):
"""
The L{keys.Key.public} method returns a public key for both
public and private keys.
"""
# NB: This assumes that the private and public keys correspond
# to each other.
privateRSAKey = keys.Key.fromString(keydata.privateRSA_openssh)
publicRSAKey = keys.Key.fromString(keydata.publicRSA_openssh)
self.assertEqual(privateRSAKey.public(), publicRSAKey.public())
privateDSAKey = keys.Key.fromString(keydata.privateDSA_openssh)
publicDSAKey = keys.Key.fromString(keydata.publicDSA_openssh)
self.assertEqual(privateDSAKey.public(), publicDSAKey.public())
privateECDSAKey = keys.Key.fromString(keydata.privateECDSA_openssh)
publicECDSAKey = keys.Key.fromString(keydata.publicECDSA_openssh)
self.assertEqual(privateECDSAKey.public(), publicECDSAKey.public())
def test_isPublic(self):
"""
The L{keys.Key.isPublic} method returns True for public keys
otherwise False.
"""
rsaKey = keys.Key.fromString(keydata.privateRSA_openssh)
dsaKey = keys.Key.fromString(keydata.privateDSA_openssh)
ecdsaKey = keys.Key.fromString(keydata.privateECDSA_openssh)
self.assertTrue(rsaKey.public().isPublic())
self.assertFalse(rsaKey.isPublic())
self.assertTrue(dsaKey.public().isPublic())
self.assertFalse(dsaKey.isPublic())
self.assertTrue(ecdsaKey.public().isPublic())
self.assertFalse(ecdsaKey.isPublic())
def _testPublicPrivateFromString(self, public, private, type, data):
self._testPublicFromString(public, type, data)
self._testPrivateFromString(private, type, data)
def _testPublicFromString(self, public, type, data):
publicKey = keys.Key.fromString(public)
self.assertTrue(publicKey.isPublic())
self.assertEqual(publicKey.type(), type)
for k, v in publicKey.data().items():
self.assertEqual(data[k], v)
def _testPrivateFromString(self, private, type, data):
privateKey = keys.Key.fromString(private)
self.assertFalse(privateKey.isPublic())
self.assertEqual(privateKey.type(), type)
for k, v in data.items():
self.assertEqual(privateKey.data()[k], v)
def test_fromOpenSSH(self):
"""
Test that keys are correctly generated from OpenSSH strings.
"""
self._testPublicPrivateFromString(keydata.publicECDSA_openssh,
keydata.privateECDSA_openssh, 'EC', keydata.ECDatanistp256)
self._testPublicPrivateFromString(keydata.publicRSA_openssh,
keydata.privateRSA_openssh, 'RSA', keydata.RSAData)
self.assertEqual(keys.Key.fromString(
keydata.privateRSA_openssh_encrypted,
passphrase=b'encrypted'),
keys.Key.fromString(keydata.privateRSA_openssh))
self.assertEqual(keys.Key.fromString(
keydata.privateRSA_openssh_alternate),
keys.Key.fromString(keydata.privateRSA_openssh))
self._testPublicPrivateFromString(keydata.publicDSA_openssh,
keydata.privateDSA_openssh, 'DSA', keydata.DSAData)
def test_fromOpenSSHErrors(self):
"""
Tests for invalid key types.
"""
badKey = b"""-----BEGIN FOO PRIVATE KEY-----
MIGkAgEBBDAtAi7I8j73WCX20qUM5hhHwHuFzYWYYILs2Sh8UZ+awNkARZ/Fu2LU
LLl5RtOQpbWgBwYFK4EEACKhZANiAATU17sA9P5FRwSknKcFsjjsk0+E3CeXPYX0
Tk/M0HK3PpWQWgrO8JdRHP9eFE9O/23P8BumwFt7F/AvPlCzVd35VfraFT0o4cCW
G0RqpQ+np31aKmeJshkcYALEchnU+tQ=
-----END EC PRIVATE KEY-----"""
self.assertRaises(keys.BadKeyError,
keys.Key._fromString_PRIVATE_OPENSSH, badKey, None)
def test_fromOpenSSH_with_whitespace(self):
"""
If key strings have trailing whitespace, it should be ignored.
"""
# from bug #3391, since our test key data doesn't have
# an issue with appended newlines
privateDSAData = b"""-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQDylESNuc61jq2yatCzZbenlr9llG+p9LhIpOLUbXhhHcwC6hrh
EZIdCKqTO0USLrGoP5uS9UHAUoeN62Z0KXXWTwOWGEQn/syyPzNJtnBorHpNUT9D
Qzwl1yUa53NNgEctpo4NoEFOx8PuU6iFLyvgHCjNn2MsuGuzkZm7sI9ZpQIVAJiR
9dPc08KLdpJyRxz8T74b4FQRAoGAGBc4Z5Y6R/HZi7AYM/iNOM8su6hrk8ypkBwR
a3Dbhzk97fuV3SF1SDrcQu4zF7c4CtH609N5nfZs2SUjLLGPWln83Ysb8qhh55Em
AcHXuROrHS/sDsnqu8FQp86MaudrqMExCOYyVPE7jaBWW+/JWFbKCxmgOCSdViUJ
esJpBFsCgYEA7+jtVvSt9yrwsS/YU1QGP5wRAiDYB+T5cK4HytzAqJKRdC5qS4zf
C7R0eKcDHHLMYO39aPnCwXjscisnInEhYGNblTDyPyiyNxAOXuC8x7luTmwzMbNJ
/ow0IqSj0VF72VJN9uSoPpFd4lLT0zN8v42RWja0M8ohWNf+YNJluPgCFE0PT4Vm
SUrCyZXsNh6VXwjs3gKQ
-----END DSA PRIVATE KEY-----"""
self.assertEqual(keys.Key.fromString(privateDSAData),
keys.Key.fromString(privateDSAData + b'\n'))
def test_fromNewerOpenSSH(self):
"""
Newer versions of OpenSSH generate encrypted keys which have a longer
IV than the older versions. These newer keys are also loaded.
"""
key = keys.Key.fromString(keydata.privateRSA_openssh_encrypted_aes,
passphrase=b'testxp')
self.assertEqual(key.type(), 'RSA')
key2 = keys.Key.fromString(
keydata.privateRSA_openssh_encrypted_aes + b'\n',
passphrase=b'testxp')
self.assertEqual(key, key2)
def test_fromOpenSSH_windows_line_endings(self):
"""
Test that keys are correctly generated from OpenSSH strings with Windows
line endings.
"""
privateDSAData = b"""-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQDylESNuc61jq2yatCzZbenlr9llG+p9LhIpOLUbXhhHcwC6hrh
EZIdCKqTO0USLrGoP5uS9UHAUoeN62Z0KXXWTwOWGEQn/syyPzNJtnBorHpNUT9D
Qzwl1yUa53NNgEctpo4NoEFOx8PuU6iFLyvgHCjNn2MsuGuzkZm7sI9ZpQIVAJiR
9dPc08KLdpJyRxz8T74b4FQRAoGAGBc4Z5Y6R/HZi7AYM/iNOM8su6hrk8ypkBwR
a3Dbhzk97fuV3SF1SDrcQu4zF7c4CtH609N5nfZs2SUjLLGPWln83Ysb8qhh55Em
AcHXuROrHS/sDsnqu8FQp86MaudrqMExCOYyVPE7jaBWW+/JWFbKCxmgOCSdViUJ
esJpBFsCgYEA7+jtVvSt9yrwsS/YU1QGP5wRAiDYB+T5cK4HytzAqJKRdC5qS4zf
C7R0eKcDHHLMYO39aPnCwXjscisnInEhYGNblTDyPyiyNxAOXuC8x7luTmwzMbNJ
/ow0IqSj0VF72VJN9uSoPpFd4lLT0zN8v42RWja0M8ohWNf+YNJluPgCFE0PT4Vm
SUrCyZXsNh6VXwjs3gKQ
-----END DSA PRIVATE KEY-----"""
self.assertEqual(
keys.Key.fromString(privateDSAData),
keys.Key.fromString(privateDSAData.replace(b'\n', b'\r\n')))
def test_fromLSHPublicUnsupportedType(self):
"""
C{BadKeyError} exception is raised when public key has an unknown
type.
"""
sexp = sexpy.pack([[b'public-key', [b'bad-key', [b'p', b'2']]]])
self.assertRaises(
keys.BadKeyError,
keys.Key.fromString, data=b'{' + base64.encodestring(sexp) + b'}',
)
def test_fromLSHPrivateUnsupportedType(self):
"""
C{BadKeyError} exception is raised when private key has an unknown
type.
"""
sexp = sexpy.pack([[b'private-key', [b'bad-key', [b'p', b'2']]]])
self.assertRaises(
keys.BadKeyError,
keys.Key.fromString, sexp,
)
def test_fromLSHRSA(self):
"""
RSA public and private keys can be generated from a LSH strings.
"""
self._testPublicPrivateFromString(
keydata.publicRSA_lsh,
keydata.privateRSA_lsh,
'RSA',
keydata.RSAData,
)
def test_fromLSHDSA(self):
"""
DSA public and private key can be generated from LSHs.
"""
self._testPublicPrivateFromString(
keydata.publicDSA_lsh,
keydata.privateDSA_lsh,
'DSA',
keydata.DSAData,
)
def test_fromAgentv3(self):
"""
Test that keys are correctly generated from Agent v3 strings.
"""
self._testPrivateFromString(keydata.privateRSA_agentv3, 'RSA',
keydata.RSAData)
self._testPrivateFromString(keydata.privateDSA_agentv3, 'DSA',
keydata.DSAData)
self.assertRaises(keys.BadKeyError, keys.Key.fromString,
b'\x00\x00\x00\x07ssh-foo'+ b'\x00\x00\x00\x01\x01'*5)
def test_fromStringErrors(self):
"""
keys.Key.fromString should raise BadKeyError when the key is invalid.
"""
self.assertRaises(keys.BadKeyError, keys.Key.fromString, b'')
# no key data with a bad key type
self.assertRaises(keys.BadKeyError, keys.Key.fromString, b'',
'bad_type')
# trying to decrypt a key which doesn't support encryption
self.assertRaises(keys.BadKeyError, keys.Key.fromString,
keydata.publicRSA_lsh, passphrase = b'unencrypted')
# trying to decrypt a key with the wrong passphrase
self.assertRaises(keys.EncryptedKeyError, keys.Key.fromString,
keys.Key(self.rsaObj).toString('openssh', b'encrypted'))
# key with no key data
self.assertRaises(keys.BadKeyError, keys.Key.fromString,
b'-----BEGIN RSA KEY-----\nwA==\n')
# key with invalid DEK Info
self.assertRaises(
keys.BadKeyError, keys.Key.fromString,
b"""-----BEGIN ENCRYPTED RSA KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: weird type
4Ed/a9OgJWHJsne7yOGWeWMzHYKsxuP9w1v0aYcp+puS75wvhHLiUnNwxz0KDi6n
T3YkKLBsoCWS68ApR2J9yeQ6R+EyS+UQDrO9nwqo3DB5BT3Ggt8S1wE7vjNLQD0H
g/SJnlqwsECNhh8aAx+Ag0m3ZKOZiRD5mCkcDQsZET7URSmFytDKOjhFn3u6ZFVB
sXrfpYc6TJtOQlHd/52JB6aAbjt6afSv955Z7enIi+5yEJ5y7oYQTaE5zrFMP7N5
9LbfJFlKXxEddy/DErRLxEjmC+t4svHesoJKc2jjjyNPiOoGGF3kJXea62vsjdNV
gMK5Eged3TBVIk2dv8rtJUvyFeCUtjQ1UJZIebScRR47KrbsIpCmU8I4/uHWm5hW
0mOwvdx1L/mqx/BHqVU9Dw2COhOdLbFxlFI92chkovkmNk4P48ziyVnpm7ME22sE
vfCMsyirdqB1mrL4CSM7FXONv+CgfBfeYVkYW8RfJac9U1L/O+JNn7yee414O/rS
hRYw4UdWnH6Gg6niklVKWNY0ZwUZC8zgm2iqy8YCYuneS37jC+OEKP+/s6HSKuqk
2bzcl3/TcZXNSM815hnFRpz0anuyAsvwPNRyvxG2/DacJHL1f6luV4B0o6W410yf
qXQx01DLo7nuyhJqoH3UGCyyXB+/QUs0mbG2PAEn3f5dVs31JMdbt+PrxURXXjKk
4cexpUcIpqqlfpIRe3RD0sDVbH4OXsGhi2kiTfPZu7mgyFxKopRbn1KwU1qKinfY
EU9O4PoTak/tPT+5jFNhaP+HrURoi/pU8EAUNSktl7xAkHYwkN/9Cm7DeBghgf3n
8+tyCGYDsB5utPD0/Xe9yx0Qhc/kMm4xIyQDyA937dk3mUvLC9vulnAP8I+Izim0
fZ182+D1bWwykoD0997mUHG/AUChWR01V1OLwRyPv2wUtiS8VNG76Y2aqKlgqP1P
V+IvIEqR4ERvSBVFzXNF8Y6j/sVxo8+aZw+d0L1Ns/R55deErGg3B8i/2EqGd3r+
0jps9BqFHHWW87n3VyEB3jWCMj8Vi2EJIfa/7pSaViFIQn8LiBLf+zxG5LTOToK5
xkN42fReDcqi3UNfKNGnv4dsplyTR2hyx65lsj4bRKDGLKOuB1y7iB0AGb0LtcAI
dcsVlcCeUquDXtqKvRnwfIMg+ZunyjqHBhj3qgRgbXbT6zjaSdNnih569aTg0Vup
VykzZ7+n/KVcGLmvX0NesdoI7TKbq4TnEIOynuG5Sf+2GpARO5bjcWKSZeN/Ybgk
gccf8Cqf6XWqiwlWd0B7BR3SymeHIaSymC45wmbgdstrbk7Ppa2Tp9AZku8M2Y7c
8mY9b+onK075/ypiwBm4L4GRNTFLnoNQJXx0OSl4FNRWsn6ztbD+jZhu8Seu10Jw
SEJVJ+gmTKdRLYORJKyqhDet6g7kAxs4EoJ25WsOnX5nNr00rit+NkMPA7xbJT+7
CfI51GQLw7pUPeO2WNt6yZO/YkzZrqvTj5FEwybkUyBv7L0gkqu9wjfDdUw0fVHE
xEm4DxjEoaIp8dW/JOzXQ2EF+WaSOgdYsw3Ac+rnnjnNptCdOEDGP6QBkt+oXj4P
-----END RSA PRIVATE KEY-----""", passphrase='encrypted')
# key with invalid encryption type
self.assertRaises(
keys.BadKeyError, keys.Key.fromString,
b"""-----BEGIN ENCRYPTED RSA KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: FOO-123-BAR,01234567
4Ed/a9OgJWHJsne7yOGWeWMzHYKsxuP9w1v0aYcp+puS75wvhHLiUnNwxz0KDi6n
T3YkKLBsoCWS68ApR2J9yeQ6R+EyS+UQDrO9nwqo3DB5BT3Ggt8S1wE7vjNLQD0H
g/SJnlqwsECNhh8aAx+Ag0m3ZKOZiRD5mCkcDQsZET7URSmFytDKOjhFn3u6ZFVB
sXrfpYc6TJtOQlHd/52JB6aAbjt6afSv955Z7enIi+5yEJ5y7oYQTaE5zrFMP7N5
9LbfJFlKXxEddy/DErRLxEjmC+t4svHesoJKc2jjjyNPiOoGGF3kJXea62vsjdNV
gMK5Eged3TBVIk2dv8rtJUvyFeCUtjQ1UJZIebScRR47KrbsIpCmU8I4/uHWm5hW
0mOwvdx1L/mqx/BHqVU9Dw2COhOdLbFxlFI92chkovkmNk4P48ziyVnpm7ME22sE
vfCMsyirdqB1mrL4CSM7FXONv+CgfBfeYVkYW8RfJac9U1L/O+JNn7yee414O/rS
hRYw4UdWnH6Gg6niklVKWNY0ZwUZC8zgm2iqy8YCYuneS37jC+OEKP+/s6HSKuqk
2bzcl3/TcZXNSM815hnFRpz0anuyAsvwPNRyvxG2/DacJHL1f6luV4B0o6W410yf
qXQx01DLo7nuyhJqoH3UGCyyXB+/QUs0mbG2PAEn3f5dVs31JMdbt+PrxURXXjKk
4cexpUcIpqqlfpIRe3RD0sDVbH4OXsGhi2kiTfPZu7mgyFxKopRbn1KwU1qKinfY
EU9O4PoTak/tPT+5jFNhaP+HrURoi/pU8EAUNSktl7xAkHYwkN/9Cm7DeBghgf3n
8+tyCGYDsB5utPD0/Xe9yx0Qhc/kMm4xIyQDyA937dk3mUvLC9vulnAP8I+Izim0
fZ182+D1bWwykoD0997mUHG/AUChWR01V1OLwRyPv2wUtiS8VNG76Y2aqKlgqP1P
V+IvIEqR4ERvSBVFzXNF8Y6j/sVxo8+aZw+d0L1Ns/R55deErGg3B8i/2EqGd3r+
0jps9BqFHHWW87n3VyEB3jWCMj8Vi2EJIfa/7pSaViFIQn8LiBLf+zxG5LTOToK5
xkN42fReDcqi3UNfKNGnv4dsplyTR2hyx65lsj4bRKDGLKOuB1y7iB0AGb0LtcAI
dcsVlcCeUquDXtqKvRnwfIMg+ZunyjqHBhj3qgRgbXbT6zjaSdNnih569aTg0Vup
VykzZ7+n/KVcGLmvX0NesdoI7TKbq4TnEIOynuG5Sf+2GpARO5bjcWKSZeN/Ybgk
gccf8Cqf6XWqiwlWd0B7BR3SymeHIaSymC45wmbgdstrbk7Ppa2Tp9AZku8M2Y7c
8mY9b+onK075/ypiwBm4L4GRNTFLnoNQJXx0OSl4FNRWsn6ztbD+jZhu8Seu10Jw
SEJVJ+gmTKdRLYORJKyqhDet6g7kAxs4EoJ25WsOnX5nNr00rit+NkMPA7xbJT+7
CfI51GQLw7pUPeO2WNt6yZO/YkzZrqvTj5FEwybkUyBv7L0gkqu9wjfDdUw0fVHE
xEm4DxjEoaIp8dW/JOzXQ2EF+WaSOgdYsw3Ac+rnnjnNptCdOEDGP6QBkt+oXj4P
-----END RSA PRIVATE KEY-----""", passphrase='encrypted')
# key with bad IV (AES)
self.assertRaises(
keys.BadKeyError, keys.Key.fromString,
b"""-----BEGIN ENCRYPTED RSA KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,01234
4Ed/a9OgJWHJsne7yOGWeWMzHYKsxuP9w1v0aYcp+puS75wvhHLiUnNwxz0KDi6n
T3YkKLBsoCWS68ApR2J9yeQ6R+EyS+UQDrO9nwqo3DB5BT3Ggt8S1wE7vjNLQD0H
g/SJnlqwsECNhh8aAx+Ag0m3ZKOZiRD5mCkcDQsZET7URSmFytDKOjhFn3u6ZFVB
sXrfpYc6TJtOQlHd/52JB6aAbjt6afSv955Z7enIi+5yEJ5y7oYQTaE5zrFMP7N5
9LbfJFlKXxEddy/DErRLxEjmC+t4svHesoJKc2jjjyNPiOoGGF3kJXea62vsjdNV
gMK5Eged3TBVIk2dv8rtJUvyFeCUtjQ1UJZIebScRR47KrbsIpCmU8I4/uHWm5hW
0mOwvdx1L/mqx/BHqVU9Dw2COhOdLbFxlFI92chkovkmNk4P48ziyVnpm7ME22sE
vfCMsyirdqB1mrL4CSM7FXONv+CgfBfeYVkYW8RfJac9U1L/O+JNn7yee414O/rS
hRYw4UdWnH6Gg6niklVKWNY0ZwUZC8zgm2iqy8YCYuneS37jC+OEKP+/s6HSKuqk
2bzcl3/TcZXNSM815hnFRpz0anuyAsvwPNRyvxG2/DacJHL1f6luV4B0o6W410yf
qXQx01DLo7nuyhJqoH3UGCyyXB+/QUs0mbG2PAEn3f5dVs31JMdbt+PrxURXXjKk
4cexpUcIpqqlfpIRe3RD0sDVbH4OXsGhi2kiTfPZu7mgyFxKopRbn1KwU1qKinfY
EU9O4PoTak/tPT+5jFNhaP+HrURoi/pU8EAUNSktl7xAkHYwkN/9Cm7DeBghgf3n
8+tyCGYDsB5utPD0/Xe9yx0Qhc/kMm4xIyQDyA937dk3mUvLC9vulnAP8I+Izim0
fZ182+D1bWwykoD0997mUHG/AUChWR01V1OLwRyPv2wUtiS8VNG76Y2aqKlgqP1P
V+IvIEqR4ERvSBVFzXNF8Y6j/sVxo8+aZw+d0L1Ns/R55deErGg3B8i/2EqGd3r+
0jps9BqFHHWW87n3VyEB3jWCMj8Vi2EJIfa/7pSaViFIQn8LiBLf+zxG5LTOToK5
xkN42fReDcqi3UNfKNGnv4dsplyTR2hyx65lsj4bRKDGLKOuB1y7iB0AGb0LtcAI
dcsVlcCeUquDXtqKvRnwfIMg+ZunyjqHBhj3qgRgbXbT6zjaSdNnih569aTg0Vup
VykzZ7+n/KVcGLmvX0NesdoI7TKbq4TnEIOynuG5Sf+2GpARO5bjcWKSZeN/Ybgk
gccf8Cqf6XWqiwlWd0B7BR3SymeHIaSymC45wmbgdstrbk7Ppa2Tp9AZku8M2Y7c
8mY9b+onK075/ypiwBm4L4GRNTFLnoNQJXx0OSl4FNRWsn6ztbD+jZhu8Seu10Jw
SEJVJ+gmTKdRLYORJKyqhDet6g7kAxs4EoJ25WsOnX5nNr00rit+NkMPA7xbJT+7
CfI51GQLw7pUPeO2WNt6yZO/YkzZrqvTj5FEwybkUyBv7L0gkqu9wjfDdUw0fVHE
xEm4DxjEoaIp8dW/JOzXQ2EF+WaSOgdYsw3Ac+rnnjnNptCdOEDGP6QBkt+oXj4P
-----END RSA PRIVATE KEY-----""", passphrase='encrypted')
# key with bad IV (DES3)
self.assertRaises(
keys.BadKeyError, keys.Key.fromString,
b"""-----BEGIN ENCRYPTED RSA KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,01234
4Ed/a9OgJWHJsne7yOGWeWMzHYKsxuP9w1v0aYcp+puS75wvhHLiUnNwxz0KDi6n
T3YkKLBsoCWS68ApR2J9yeQ6R+EyS+UQDrO9nwqo3DB5BT3Ggt8S1wE7vjNLQD0H
g/SJnlqwsECNhh8aAx+Ag0m3ZKOZiRD5mCkcDQsZET7URSmFytDKOjhFn3u6ZFVB
sXrfpYc6TJtOQlHd/52JB6aAbjt6afSv955Z7enIi+5yEJ5y7oYQTaE5zrFMP7N5
9LbfJFlKXxEddy/DErRLxEjmC+t4svHesoJKc2jjjyNPiOoGGF3kJXea62vsjdNV
gMK5Eged3TBVIk2dv8rtJUvyFeCUtjQ1UJZIebScRR47KrbsIpCmU8I4/uHWm5hW
0mOwvdx1L/mqx/BHqVU9Dw2COhOdLbFxlFI92chkovkmNk4P48ziyVnpm7ME22sE
vfCMsyirdqB1mrL4CSM7FXONv+CgfBfeYVkYW8RfJac9U1L/O+JNn7yee414O/rS
hRYw4UdWnH6Gg6niklVKWNY0ZwUZC8zgm2iqy8YCYuneS37jC+OEKP+/s6HSKuqk
2bzcl3/TcZXNSM815hnFRpz0anuyAsvwPNRyvxG2/DacJHL1f6luV4B0o6W410yf
qXQx01DLo7nuyhJqoH3UGCyyXB+/QUs0mbG2PAEn3f5dVs31JMdbt+PrxURXXjKk
4cexpUcIpqqlfpIRe3RD0sDVbH4OXsGhi2kiTfPZu7mgyFxKopRbn1KwU1qKinfY
EU9O4PoTak/tPT+5jFNhaP+HrURoi/pU8EAUNSktl7xAkHYwkN/9Cm7DeBghgf3n
8+tyCGYDsB5utPD0/Xe9yx0Qhc/kMm4xIyQDyA937dk3mUvLC9vulnAP8I+Izim0
fZ182+D1bWwykoD0997mUHG/AUChWR01V1OLwRyPv2wUtiS8VNG76Y2aqKlgqP1P
V+IvIEqR4ERvSBVFzXNF8Y6j/sVxo8+aZw+d0L1Ns/R55deErGg3B8i/2EqGd3r+
0jps9BqFHHWW87n3VyEB3jWCMj8Vi2EJIfa/7pSaViFIQn8LiBLf+zxG5LTOToK5
xkN42fReDcqi3UNfKNGnv4dsplyTR2hyx65lsj4bRKDGLKOuB1y7iB0AGb0LtcAI
dcsVlcCeUquDXtqKvRnwfIMg+ZunyjqHBhj3qgRgbXbT6zjaSdNnih569aTg0Vup
VykzZ7+n/KVcGLmvX0NesdoI7TKbq4TnEIOynuG5Sf+2GpARO5bjcWKSZeN/Ybgk
gccf8Cqf6XWqiwlWd0B7BR3SymeHIaSymC45wmbgdstrbk7Ppa2Tp9AZku8M2Y7c
8mY9b+onK075/ypiwBm4L4GRNTFLnoNQJXx0OSl4FNRWsn6ztbD+jZhu8Seu10Jw
SEJVJ+gmTKdRLYORJKyqhDet6g7kAxs4EoJ25WsOnX5nNr00rit+NkMPA7xbJT+7
CfI51GQLw7pUPeO2WNt6yZO/YkzZrqvTj5FEwybkUyBv7L0gkqu9wjfDdUw0fVHE
xEm4DxjEoaIp8dW/JOzXQ2EF+WaSOgdYsw3Ac+rnnjnNptCdOEDGP6QBkt+oXj4P
-----END RSA PRIVATE KEY-----""", passphrase='encrypted')
def test_fromFile(self):
"""
Test that fromFile works correctly.
"""
self.assertEqual(keys.Key.fromFile(self.keyFile),
keys.Key.fromString(keydata.privateRSA_lsh))
self.assertRaises(keys.BadKeyError, keys.Key.fromFile,
self.keyFile, 'bad_type')
self.assertRaises(keys.BadKeyError, keys.Key.fromFile,
self.keyFile, passphrase='unencrypted')
def test_init(self):
"""
Test that the PublicKey object is initialized correctly.
"""
obj = keys.Key._fromRSAComponents(n=long(5), e=long(3))._keyObject
key = keys.Key(obj)
self.assertEqual(key._keyObject, obj)
def test_equal(self):
"""
Test that Key objects are compared correctly.
"""
rsa1 = keys.Key(self.rsaObj)
rsa2 = keys.Key(self.rsaObj)
rsa3 = keys.Key(
keys.Key._fromRSAComponents(n=long(5), e=long(3))._keyObject)
dsa = keys.Key(self.dsaObj)
self.assertTrue(rsa1 == rsa2)
self.assertFalse(rsa1 == rsa3)
self.assertFalse(rsa1 == dsa)
self.assertFalse(rsa1 == object)
self.assertFalse(rsa1 == None)
def test_notEqual(self):
"""
Test that Key objects are not-compared correctly.
"""
rsa1 = keys.Key(self.rsaObj)
rsa2 = keys.Key(self.rsaObj)
rsa3 = keys.Key(
keys.Key._fromRSAComponents(n=long(5), e=long(3))._keyObject)
dsa = keys.Key(self.dsaObj)
self.assertFalse(rsa1 != rsa2)
self.assertTrue(rsa1 != rsa3)
self.assertTrue(rsa1 != dsa)
self.assertTrue(rsa1 != object)
self.assertTrue(rsa1 != None)
def test_dataError(self):
"""
The L{keys.Key.data} method raises RuntimeError for bad keys.
"""
badKey = keys.Key(b'')
self.assertRaises(RuntimeError, badKey.data)
def test_fingerprintdefault(self):
"""
Test that the fingerprint method returns fingerprint in
L{FingerprintFormats.MD5-HEX} format by default.
"""
self.assertEqual(keys.Key(self.rsaObj).fingerprint(),
'85:25:04:32:58:55:96:9f:57:ee:fb:a8:1a:ea:69:da')
self.assertEqual(keys.Key(self.dsaObj).fingerprint(),
'63:15:b3:0e:e6:4f:50:de:91:48:3d:01:6b:b3:13:c1')
def test_fingerprint_md5_hex(self):
"""
fingerprint method generates key fingerprint in
L{FingerprintFormats.MD5-HEX} format if explicitly specified.
"""
self.assertEqual(
keys.Key(self.rsaObj).fingerprint(
keys.FingerprintFormats.MD5_HEX),
'85:25:04:32:58:55:96:9f:57:ee:fb:a8:1a:ea:69:da')
self.assertEqual(
keys.Key(self.dsaObj).fingerprint(
keys.FingerprintFormats.MD5_HEX),
'63:15:b3:0e:e6:4f:50:de:91:48:3d:01:6b:b3:13:c1')
def test_fingerprintsha256(self):
"""
fingerprint method generates key fingerprint in
L{FingerprintFormats.SHA256-BASE64} format if explicitly specified.
"""
self.assertEqual(
keys.Key(self.rsaObj).fingerprint(
keys.FingerprintFormats.SHA256_BASE64),
'FBTCOoknq0mHy+kpfnY9tDdcAJuWtCpuQMaV3EsvbUI=')
self.assertEqual(
keys.Key(self.dsaObj).fingerprint(
keys.FingerprintFormats.SHA256_BASE64),
'Wz5o2YbKyxOEcJn1au/UaALSVruUzfz0vaLI1xiIGyY=')
def test_fingerprintBadFormat(self):
"""
A C{BadFingerPrintFormat} error is raised when unsupported
formats are requested.
"""
with self.assertRaises(keys.BadFingerPrintFormat) as em:
keys.Key(self.rsaObj).fingerprint('sha256-base')
self.assertEqual('Unsupported fingerprint format: sha256-base',
em.exception.args[0])
def test_type(self):
"""
Test that the type method returns the correct type for an object.
"""
self.assertEqual(keys.Key(self.rsaObj).type(), 'RSA')
self.assertEqual(keys.Key(self.rsaObj).sshType(), b'ssh-rsa')
self.assertEqual(keys.Key(self.dsaObj).type(), 'DSA')
self.assertEqual(keys.Key(self.dsaObj).sshType(), b'ssh-dss')
self.assertEqual(keys.Key(self.ecObj).type(), 'EC')
self.assertEqual(keys.Key(self.ecObj).sshType(),
keydata.ECDatanistp256['curve'])
self.assertRaises(RuntimeError, keys.Key(None).type)
self.assertRaises(RuntimeError, keys.Key(None).sshType)
self.assertRaises(RuntimeError, keys.Key(self).type)
self.assertRaises(RuntimeError, keys.Key(self).sshType)
def test_fromBlobUnsupportedType(self):
"""
A C{BadKeyError} error is raised whey the blob has an unsupported
key type.
"""
badBlob = common.NS(b'ssh-bad')
self.assertRaises(keys.BadKeyError,
keys.Key.fromString, badBlob)
def test_fromBlobRSA(self):
"""
A public RSA key is correctly generated from a public key blob.
"""
rsaPublicData = {
'n': keydata.RSAData['n'],
'e': keydata.RSAData['e'],
}
rsaBlob = (
common.NS(b'ssh-rsa') +
common.MP(rsaPublicData['e']) +
common.MP(rsaPublicData['n'])
)
rsaKey = keys.Key.fromString(rsaBlob)
self.assertTrue(rsaKey.isPublic())
self.assertEqual(rsaPublicData, rsaKey.data())
def test_fromBlobDSA(self):
"""
A public DSA key is correctly generated from a public key blob.
"""
dsaPublicData = {
'p': keydata.DSAData['p'],
'q': keydata.DSAData['q'],
'g': keydata.DSAData['g'],
'y': keydata.DSAData['y'],
}
dsaBlob = (
common.NS(b'ssh-dss') +
common.MP(dsaPublicData['p']) +
common.MP(dsaPublicData['q']) +
common.MP(dsaPublicData['g']) +
common.MP(dsaPublicData['y'])
)
dsaKey = keys.Key.fromString(dsaBlob)
self.assertTrue(dsaKey.isPublic())
self.assertEqual(dsaPublicData, dsaKey.data())
def test_fromBlobECDSA(self):
"""
Key.fromString generates ECDSA keys from blobs.
"""
from cryptography import utils
ecPublicData = {
'x': keydata.ECDatanistp256['x'],
'y': keydata.ECDatanistp256['y'],
'curve': keydata.ECDatanistp256['curve']
}
ecblob = (common.NS(ecPublicData['curve']) +
common.NS(ecPublicData['curve'][-8:]) +
common.NS(b'\x04' +
utils.int_to_bytes(ecPublicData['x'], 32) +
utils.int_to_bytes(ecPublicData['y'], 32))
)
eckey = keys.Key.fromString(ecblob)
self.assertTrue(eckey.isPublic())
self.assertEqual(ecPublicData, eckey.data())
def test_fromPrivateBlobUnsupportedType(self):
"""
C{BadKeyError} is raised when loading a private blob with an
unsupported type.
"""
badBlob = common.NS(b'ssh-bad')
self.assertRaises(
keys.BadKeyError, keys.Key._fromString_PRIVATE_BLOB, badBlob)
def test_fromPrivateBlobRSA(self):
"""
A private RSA key is correctly generated from a private key blob.
"""
rsaBlob = (
common.NS(b'ssh-rsa') +
common.MP(keydata.RSAData['n']) +
common.MP(keydata.RSAData['e']) +
common.MP(keydata.RSAData['d']) +
common.MP(keydata.RSAData['u']) +
common.MP(keydata.RSAData['p']) +
common.MP(keydata.RSAData['q'])
)
rsaKey = keys.Key._fromString_PRIVATE_BLOB(rsaBlob)
self.assertFalse(rsaKey.isPublic())
self.assertEqual(keydata.RSAData, rsaKey.data())
def test_fromPrivateBlobDSA(self):
"""
A private DSA key is correctly generated from a private key blob.
"""
dsaBlob = (
common.NS(b'ssh-dss') +
common.MP(keydata.DSAData['p']) +
common.MP(keydata.DSAData['q']) +
common.MP(keydata.DSAData['g']) +
common.MP(keydata.DSAData['y']) +
common.MP(keydata.DSAData['x'])
)
dsaKey = keys.Key._fromString_PRIVATE_BLOB(dsaBlob)
self.assertFalse(dsaKey.isPublic())
self.assertEqual(keydata.DSAData, dsaKey.data())
def test_fromPrivateBlobECDSA(self):
"""
A private EC key is correctly generated from a private key blob.
"""
ecblob = (
common.NS(keydata.ECDatanistp256['curve']) +
common.MP(keydata.ECDatanistp256['x']) +
common.MP(keydata.ECDatanistp256['y']) +
common.MP(keydata.ECDatanistp256['privateValue'])
)
eckey = keys.Key._fromString_PRIVATE_BLOB(ecblob)
self.assertFalse(eckey.isPublic())
self.assertEqual(keydata.ECDatanistp256, eckey.data())
def test_blobRSA(self):
"""
Return the over-the-wire SSH format of the RSA public key.
"""
self.assertEqual(
keys.Key(self.rsaObj).blob(),
common.NS(b'ssh-rsa') +
common.MP(self.rsaObj.private_numbers().public_numbers.e) +
common.MP(self.rsaObj.private_numbers().public_numbers.n)
)
def test_blobDSA(self):
"""
Return the over-the-wire SSH format of the DSA public key.
"""
publicNumbers = self.dsaObj.private_numbers().public_numbers
self.assertEqual(
keys.Key(self.dsaObj).blob(),
common.NS(b'ssh-dss') +
common.MP(publicNumbers.parameter_numbers.p) +
common.MP(publicNumbers.parameter_numbers.q) +
common.MP(publicNumbers.parameter_numbers.g) +
common.MP(publicNumbers.y)
)
def test_blobEC(self):
"""
Return the over-the-wire SSH format of the EC public key.
"""
from cryptography import utils
byteLength = (self.ecObj.curve.key_size + 7) // 8
self.assertEqual(
keys.Key(self.ecObj).blob(),
common.NS(keydata.ECDatanistp256['curve']) +
common.NS(keydata.ECDatanistp256['curve'][-8:]) +
common.NS(b'\x04' +
utils.int_to_bytes(
self.ecObj.private_numbers().public_numbers.x, byteLength) +
utils.int_to_bytes(
self.ecObj.private_numbers().public_numbers.y, byteLength))
)
def test_blobNoKey(self):
"""
C{RuntimeError} is raised when the blob is requested for a Key
which is not wrapping anything.
"""
badKey = keys.Key(None)
self.assertRaises(RuntimeError, badKey.blob)
def test_privateBlobRSA(self):
"""
L{keys.Key.privateBlob} returns the SSH protocol-level format of an
RSA private key.
"""
from cryptography.hazmat.primitives.asymmetric import rsa
numbers = self.rsaObj.private_numbers()
u = rsa.rsa_crt_iqmp(numbers.q, numbers.p)
self.assertEqual(
keys.Key(self.rsaObj).privateBlob(),
common.NS(b'ssh-rsa') +
common.MP(self.rsaObj.private_numbers().public_numbers.n) +
common.MP(self.rsaObj.private_numbers().public_numbers.e) +
common.MP(self.rsaObj.private_numbers().d) +
common.MP(u) +
common.MP(self.rsaObj.private_numbers().p) +
common.MP(self.rsaObj.private_numbers().q)
)
def test_privateBlobDSA(self):
"""
L{keys.Key.privateBlob} returns the SSH protocol-level format of a DSA
private key.
"""
publicNumbers = self.dsaObj.private_numbers().public_numbers
self.assertEqual(
keys.Key(self.dsaObj).privateBlob(),
common.NS(b'ssh-dss') +
common.MP(publicNumbers.parameter_numbers.p) +
common.MP(publicNumbers.parameter_numbers.q) +
common.MP(publicNumbers.parameter_numbers.g) +
common.MP(publicNumbers.y) +
common.MP(self.dsaObj.private_numbers().x)
)
def test_privateBlobEC(self):
"""
L{keys.Key.privateBlob} returns the SSH ptotocol-level format of EC
private key.
"""
self.assertEqual(
keys.Key(self.ecObj).privateBlob(),
common.NS(keydata.ECDatanistp256['curve']) +
common.MP(self.ecObj.private_numbers().public_numbers.x) +
common.MP(self.ecObj.private_numbers().public_numbers.y) +
common.MP(self.ecObj.private_numbers().private_value)
)
def test_privateBlobNoKeyObject(self):
"""
Raises L{RuntimeError} if the underlying key object does not exists.
"""
badKey = keys.Key(None)
self.assertRaises(RuntimeError, badKey.privateBlob)
def test_toOpenSSHRSA(self):
"""
L{keys.Key.toString} serializes an RSA key in OpenSSH format.
"""
key = keys.Key.fromString(keydata.privateRSA_agentv3)
self.assertEqual(key.toString('openssh'), keydata.privateRSA_openssh)
self.assertEqual(key.toString('openssh', b'encrypted'),
keydata.privateRSA_openssh_encrypted)
self.assertEqual(key.public().toString('openssh'),
keydata.publicRSA_openssh[:-8]) # no comment
self.assertEqual(key.public().toString('openssh', b'comment'),
keydata.publicRSA_openssh)
def test_toOpenSSHDSA(self):
"""
L{keys.Key.toString} serializes a DSA key in OpenSSH format.
"""
key = keys.Key.fromString(keydata.privateDSA_lsh)
self.assertEqual(key.toString('openssh'), keydata.privateDSA_openssh)
self.assertEqual(key.public().toString('openssh', b'comment'),
keydata.publicDSA_openssh)
self.assertEqual(key.public().toString('openssh'),
keydata.publicDSA_openssh[:-8]) # no comment
def test_toOpenSSHECDSA(self):
"""
L{keys.Key.toString} serializes a ECDSA key in OpenSSH format.
"""
key = keys.Key.fromString(keydata.privateECDSA_openssh)
self.assertEqual(key.public().toString('openssh', b'comment'),
keydata.publicECDSA_openssh)
self.assertEqual(key.public().toString('openssh'),
keydata.publicECDSA_openssh[:-8]) # no comment
def test_toLSHRSA(self):
"""
L{keys.Key.toString} serializes an RSA key in LSH format.
"""
key = keys.Key.fromString(keydata.privateRSA_openssh)
self.assertEqual(key.toString('lsh'), keydata.privateRSA_lsh)
self.assertEqual(key.public().toString('lsh'),
keydata.publicRSA_lsh)
def test_toLSHDSA(self):
"""
L{keys.Key.toString} serializes a DSA key in LSH format.
"""
key = keys.Key.fromString(keydata.privateDSA_openssh)
self.assertEqual(key.toString('lsh'), keydata.privateDSA_lsh)
self.assertEqual(key.public().toString('lsh'),
keydata.publicDSA_lsh)
def test_toAgentv3RSA(self):
"""
L{keys.Key.toString} serializes an RSA key in Agent v3 format.
"""
key = keys.Key.fromString(keydata.privateRSA_openssh)
self.assertEqual(key.toString('agentv3'), keydata.privateRSA_agentv3)
def test_toAgentv3DSA(self):
"""
L{keys.Key.toString} serializes a DSA key in Agent v3 format.
"""
key = keys.Key.fromString(keydata.privateDSA_openssh)
self.assertEqual(key.toString('agentv3'), keydata.privateDSA_agentv3)
def test_toStringErrors(self):
"""
L{keys.Key.toString} raises L{keys.BadKeyError} when passed an invalid
format type.
"""
self.assertRaises(keys.BadKeyError, keys.Key(self.rsaObj).toString,
'bad_type')
def test_signAndVerifyRSA(self):
"""
Signed data can be verified using RSA.
"""
data = b'some-data'
key = keys.Key.fromString(keydata.privateRSA_openssh)
signature = key.sign(data)
self.assertTrue(key.public().verify(signature, data))
self.assertTrue(key.verify(signature, data))
def test_signAndVerifyDSA(self):
"""
Signed data can be verified using DSA.
"""
data = b'some-data'
key = keys.Key.fromString(keydata.privateDSA_openssh)
signature = key.sign(data)
self.assertTrue(key.public().verify(signature, data))
self.assertTrue(key.verify(signature, data))
def test_signAndVerifyEC(self):
"""
Signed data can be verified using EC.
"""
data = b'some-data'
key = keys.Key.fromString(keydata.privateECDSA_openssh)
signature = key.sign(data)
key384 = keys.Key.fromString(keydata.privateECDSA_openssh384)
signature384 = key384.sign(data)
key521 = keys.Key.fromString(keydata.privateECDSA_openssh521)
signature521 = key521.sign(data)
self.assertTrue(key.public().verify(signature, data))
self.assertTrue(key.verify(signature, data))
self.assertTrue(key384.public().verify(signature384, data))
self.assertTrue(key384.verify(signature384, data))
self.assertTrue(key521.public().verify(signature521, data))
self.assertTrue(key521.verify(signature521, data))
def test_verifyRSA(self):
"""
A known-good RSA signature verifies successfully.
"""
key = keys.Key.fromString(keydata.publicRSA_openssh)
self.assertTrue(key.verify(self.rsaSignature, b''))
self.assertFalse(key.verify(self.rsaSignature, b'a'))
self.assertFalse(key.verify(self.dsaSignature, b''))
def test_verifyDSA(self):
"""
A known-good DSA signature verifies successfully.
"""
key = keys.Key.fromString(keydata.publicDSA_openssh)
self.assertTrue(key.verify(self.dsaSignature, b''))
self.assertFalse(key.verify(self.dsaSignature, b'a'))
self.assertFalse(key.verify(self.rsaSignature, b''))
def test_verifyDSANoPrefix(self):
"""
Some commercial SSH servers send DSA keys as 2 20-byte numbers;
they are still verified as valid keys.
"""
key = keys.Key.fromString(keydata.publicDSA_openssh)
self.assertTrue(key.verify(self.dsaSignature[-40:], b''))
def test_reprPrivateRSA(self):
"""
The repr of a L{keys.Key} contains all of the RSA components for an RSA
private key.
"""
self.assertEqual(repr(keys.Key(self.rsaObj)),
"""<RSA Private Key (2048 bits)
attr d:
\t21:4c:08:66:a2:28:d5:b4:fb:8e:0f:72:1b:85:09:
\t00:b9:f2:4e:37:f0:1c:57:4b:e3:51:7f:9e:23:a7:
\te4:3a:98:55:1b:ea:8b:7a:98:1e:bc:d8:ba:b1:f9:
\t89:12:18:60:ac:e8:cc:0b:4e:09:5a:40:6a:ba:2f:
\t99:f8:b3:24:60:84:b9:ce:69:95:9a:f9:e2:fc:1f:
\t51:4d:27:15:db:2b:27:ad:ef:b4:69:ac:be:7d:10:
\teb:86:47:70:73:b4:00:87:95:15:3b:37:f9:e7:14:
\te7:80:bb:68:1e:1b:e6:dd:bb:73:63:b9:67:e6:b2:
\t27:7f:cf:cf:30:9b:c2:98:fd:d9:18:36:2f:36:2e:
\tf1:3d:81:7a:9f:e1:03:2d:47:db:34:51:62:39:dd:
\t4f:e9:ac:a8:8b:d9:d6:f3:84:c4:17:b9:71:9d:06:
\t08:42:78:4d:bb:c5:2a:f4:c3:58:cd:55:2b:ed:be:
\t33:5f:04:ea:7b:e6:04:24:63:f2:2d:d7:3d:1b:6c:
\td5:9c:63:43:2f:92:88:8d:3e:6e:da:18:37:d8:0f:
\t25:67:89:1d:b9:46:34:5e:c9:ce:c4:8b:ed:92:5a:
\t33:07:0f:df:86:08:f9:92:e9:db:eb:38:08:36:c9:
\tcd:cd:0a:01:48:5b:39:3e:7a:ca:c6:80:a9:dc:d4:
\t39
attr e:
\t01:00:01
attr n:
\t00:d5:6a:ac:78:23:d6:d6:1b:ec:25:a1:50:c4:77:
\t63:50:84:45:01:55:42:14:2a:2a:e0:d0:60:ee:d4:
\te9:a3:ad:4a:fa:39:06:5e:84:55:75:5f:00:36:bf:
\t6f:aa:2a:3f:83:26:37:c1:69:2e:5b:fd:f0:f3:d2:
\t7d:d6:98:cd:3a:40:78:d5:ca:a8:18:c0:11:93:24:
\t09:0c:81:4c:8f:f7:9c:ed:13:16:6a:a4:04:e9:49:
\t77:c3:e4:55:64:b3:79:68:9e:2c:08:eb:ac:e8:04:
\t2d:21:77:05:a7:8e:ef:53:30:0d:a5:e5:bb:3d:6a:
\te2:09:36:6f:fd:34:d3:7d:6f:46:ff:87:da:a9:29:
\t27:aa:ff:ad:f5:85:e6:3e:1a:b8:7a:1d:4a:b1:ea:
\tc0:5a:f7:30:df:1f:c2:a4:e4:ef:3f:91:49:96:40:
\td5:19:77:2d:37:c3:5e:ec:9d:a6:3a:44:a5:c2:a4:
\t29:dd:d5:ba:9c:3d:45:b3:c6:2c:18:64:d5:ba:3d:
\tdf:ab:7f:cd:42:ac:a7:f1:18:0b:a0:58:15:62:0b:
\ta4:2a:6e:43:c3:e4:04:9f:35:a3:47:8e:46:ed:33:
\ta5:65:bd:bc:3b:29:6e:02:0b:57:df:74:e8:13:b4:
\t37:35:7e:83:5f:20:26:60:a6:dc:ad:8b:c6:6c:79:
\t98:f7
attr p:
\t00:d9:70:06:d8:e2:bc:d4:78:91:50:94:d4:c1:1b:
\t89:38:6c:46:64:5a:51:a0:9a:07:3d:48:8f:03:51:
\tcc:6b:12:8e:7d:1a:b1:65:e7:71:75:39:e0:32:05:
\t75:8d:18:4c:af:93:b1:49:b1:66:5f:78:62:7a:d1:
\t0c:ca:e6:4d:43:b3:9c:f4:6b:7d:e6:0c:98:dc:cf:
\t21:62:8e:d5:2e:12:de:04:ae:d7:24:6e:83:31:a2:
\t15:a2:44:3d:22:a9:62:26:22:b9:b2:ed:54:0a:9d:
\t08:83:a7:07:0d:ff:19:18:8e:d8:ab:1d:da:48:9c:
\t31:68:11:a1:66:6d:e3:d8:1d
attr q:
\t00:fb:44:17:8b:a4:36:be:1e:37:1d:a7:f6:61:6c:
\t04:c4:aa:dd:78:3e:07:8c:1e:33:02:ae:03:14:87:
\t83:7a:e5:9e:7d:08:67:a8:f2:aa:bf:12:70:cf:72:
\ta9:a7:c7:0b:1d:88:d5:20:fd:9c:63:ca:47:30:55:
\t4e:8b:c4:cf:f4:7f:16:a4:92:12:74:a1:09:c2:c4:
\t6e:9c:8c:33:ef:a5:e5:f7:e0:2b:ad:4f:5c:11:aa:
\t1a:84:37:5b:fd:7a:ea:c3:cd:7c:b0:c8:e4:1f:54:
\t63:b5:c7:af:df:f4:09:a7:fc:c7:25:fc:5c:e9:91:
\td7:92:c5:98:1e:56:d3:b1:23
attr u:
\t00:85:4b:1b:7a:9b:12:10:37:9e:1f:ad:5e:da:fe:
\tc6:96:fe:df:35:6b:b9:34:e2:16:97:92:26:09:bd:
\tbd:70:20:03:a7:35:bd:2d:1b:a0:d2:07:47:2b:d4:
\tde:a8:a8:07:07:1b:b8:04:20:a7:27:41:3c:6c:39:
\t39:e9:41:ce:e7:17:1d:d1:4c:5c:bc:3d:d2:26:26:
\tfe:6a:d6:fd:48:72:ae:46:fa:7b:c3:d3:19:60:44:
\t1d:a5:13:a7:80:f5:63:29:d4:7a:5d:06:07:16:5d:
\tf6:8b:3d:cb:64:3a:e2:84:5a:4d:8c:06:2d:2d:9d:
\t1c:eb:83:4c:78:3d:79:54:ce>""")
def test_reprPublicRSA(self):
"""
The repr of a L{keys.Key} contains all of the RSA components for an RSA
public key.
"""
self.assertEqual(repr(keys.Key(self.rsaObj).public()),
"""<RSA Public Key (2048 bits)
attr e:
\t01:00:01
attr n:
\t00:d5:6a:ac:78:23:d6:d6:1b:ec:25:a1:50:c4:77:
\t63:50:84:45:01:55:42:14:2a:2a:e0:d0:60:ee:d4:
\te9:a3:ad:4a:fa:39:06:5e:84:55:75:5f:00:36:bf:
\t6f:aa:2a:3f:83:26:37:c1:69:2e:5b:fd:f0:f3:d2:
\t7d:d6:98:cd:3a:40:78:d5:ca:a8:18:c0:11:93:24:
\t09:0c:81:4c:8f:f7:9c:ed:13:16:6a:a4:04:e9:49:
\t77:c3:e4:55:64:b3:79:68:9e:2c:08:eb:ac:e8:04:
\t2d:21:77:05:a7:8e:ef:53:30:0d:a5:e5:bb:3d:6a:
\te2:09:36:6f:fd:34:d3:7d:6f:46:ff:87:da:a9:29:
\t27:aa:ff:ad:f5:85:e6:3e:1a:b8:7a:1d:4a:b1:ea:
\tc0:5a:f7:30:df:1f:c2:a4:e4:ef:3f:91:49:96:40:
\td5:19:77:2d:37:c3:5e:ec:9d:a6:3a:44:a5:c2:a4:
\t29:dd:d5:ba:9c:3d:45:b3:c6:2c:18:64:d5:ba:3d:
\tdf:ab:7f:cd:42:ac:a7:f1:18:0b:a0:58:15:62:0b:
\ta4:2a:6e:43:c3:e4:04:9f:35:a3:47:8e:46:ed:33:
\ta5:65:bd:bc:3b:29:6e:02:0b:57:df:74:e8:13:b4:
\t37:35:7e:83:5f:20:26:60:a6:dc:ad:8b:c6:6c:79:
\t98:f7>""")
def test_reprPublicECDSA(self):
"""
The repr of a L{keys.Key} contains all the OpenSSH format for an ECDSA
public key.
"""
self.assertEqual(repr(keys.Key(self.ecObj).public()),
"""<Elliptic Curve Public Key (256 bits)
curve:
\tecdsa-sha2-nistp256
x:
\t76282513020392096317118503144964731774299773481750550543382904345687059013883
y:""" +
"\n\t8154319786460285263226566476944164753434437589431431968106113715931064" +
"6683104>\n")
def test_reprPrivateECDSA(self):
"""
The repr of a L{keys.Key} contains all the OpenSSH format for an ECDSA
private key.
"""
self.assertEqual(repr(keys.Key(self.ecObj)),
"""<Elliptic Curve Private Key (256 bits)
curve:
\tecdsa-sha2-nistp256
privateValue:
\t34638743477210341700964008455655698253555655678826059678074967909361042656500
x:
\t76282513020392096317118503144964731774299773481750550543382904345687059013883
y:""" +
"\n\t8154319786460285263226566476944164753434437589431431968106113715931064" +
"6683104>\n")
class PersistentRSAKeyTests(unittest.TestCase):
"""
Tests for L{keys._getPersistentRSAKey}.
"""
if cryptography is None:
skip = skipCryptography
def test_providedArguments(self):
"""
L{keys._getPersistentRSAKey} will put the key in
C{directory}/C{filename}, with the key length of C{keySize}.
"""
tempDir = FilePath(self.mktemp())
keyFile = tempDir.child("mykey.pem")
key = keys._getPersistentRSAKey(keyFile, keySize=512)
self.assertEqual(key.size(), 512)
self.assertTrue(keyFile.exists())
def test_noRegeneration(self):
"""
L{keys._getPersistentRSAKey} will not regenerate the key if the key
already exists.
"""
tempDir = FilePath(self.mktemp())
keyFile = tempDir.child("mykey.pem")
key = keys._getPersistentRSAKey(keyFile, keySize=512)
self.assertEqual(key.size(), 512)
self.assertTrue(keyFile.exists())
keyContent = keyFile.getContent()
# Set the key size to 1024 bits. Since it exists already, it will find
# the 512 bit key, and not generate a 1024 bit key.
key = keys._getPersistentRSAKey(keyFile, keySize=1024)
self.assertEqual(key.size(), 512)
self.assertEqual(keyFile.getContent(), keyContent)
def test_keySizeZero(self):
"""
If the key generated by L{keys.getPersistentRSAKey} is set to None
the key size should then become 0.
"""
tempDir = FilePath(self.mktemp())
keyFile = tempDir.child("mykey.pem")
key = keys._getPersistentRSAKey(keyFile, keySize=512)
key._keyObject = None
self.assertEqual( key.size(), 0)