1#
2# Copyright (C) 2010-2017 Samuel Abels
3# The MIT License (MIT)
4#
5# Permission is hereby granted, free of charge, to any person obtaining
6# a copy of this software and associated documentation files
7# (the "Software"), to deal in the Software without restriction,
8# including without limitation the rights to use, copy, modify, merge,
9# publish, distribute, sublicense, and/or sell copies of the Software,
10# and to permit persons to whom the Software is furnished to do so,
11# subject to the following conditions:
12#
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23"""
24Represents a private key.
25"""
26from builtins import object
27from paramiko import RSAKey, DSSKey
28from paramiko.ssh_exception import SSHException
29
30
31class PrivateKey(object):
32
33    """
34    Represents a cryptographic key, and may be used to authenticate
35    useing :class:`Exscript.protocols`.
36    """
37    keytypes = set()
38
39    def __init__(self, keytype='rsa'):
40        """
41        Constructor. Supported key types are provided by their respective
42        protocol adapters and can be retrieved from the PrivateKey.keytypes
43        class attribute.
44
45        :type  keytype: string
46        :param keytype: The key type.
47        """
48        if keytype not in self.keytypes:
49            raise TypeError('unsupported key type: ' + repr(keytype))
50        self.keytype = keytype
51        self.filename = None
52        self.password = None
53
54    @staticmethod
55    def from_file(filename, password='', keytype=None):
56        """
57        Returns a new PrivateKey instance with the given attributes.
58        If keytype is None, we attempt to automatically detect the type.
59
60        :type  filename: string
61        :param filename: The key file name.
62        :type  password: string
63        :param password: The key password.
64        :type  keytype: string
65        :param keytype: The key type.
66        :rtype:  PrivateKey
67        :return: The new key.
68        """
69        if keytype is None:
70            try:
71                key = RSAKey.from_private_key_file(filename)
72                keytype = 'rsa'
73            except SSHException as e:
74                try:
75                    key = DSSKey.from_private_key_file(filename)
76                    keytype = 'dss'
77                except SSHException as e:
78                    msg = 'not a recognized private key: ' + repr(filename)
79                    raise ValueError(msg)
80        key = PrivateKey(keytype)
81        key.filename = filename
82        key.password = password
83        return key
84
85    def get_type(self):
86        """
87        Returns the type of the key, e.g. RSA or DSA.
88
89        :rtype:  string
90        :return: The key type
91        """
92        return self.keytype
93
94    def set_filename(self, filename):
95        """
96        Sets the name of the key file to use.
97
98        :type  filename: string
99        :param filename: The key filename.
100        """
101        self.filename = filename
102
103    def get_filename(self):
104        """
105        Returns the name of the key file.
106
107        :rtype:  string
108        :return: The key password.
109        """
110        return self.filename
111
112    def set_password(self, password):
113        """
114        Defines the password used for decrypting the key.
115
116        :type  password: string
117        :param password: The key password.
118        """
119        self.password = password
120
121    def get_password(self):
122        """
123        Returns the password for the key.
124
125        :rtype:  string
126        :return: The key password.
127        """
128        return self.password
129