• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Author: Trevor Perrin
2# See the LICENSE file for legal information regarding use of this file.
3
4"""Factory functions for asymmetric cryptography.
5@sort: generateRSAKey, parsePEMKey, parseAsPublicKey
6"""
7
8from .compat import *
9
10from .rsakey import RSAKey
11from .python_rsakey import Python_RSAKey
12from tlslite.utils import cryptomath
13
14if cryptomath.m2cryptoLoaded:
15    from .openssl_rsakey import OpenSSL_RSAKey
16
17if cryptomath.pycryptoLoaded:
18    from .pycrypto_rsakey import PyCrypto_RSAKey
19
20# **************************************************************************
21# Factory Functions for RSA Keys
22# **************************************************************************
23
24def generateRSAKey(bits, implementations=["openssl", "python"]):
25    """Generate an RSA key with the specified bit length.
26
27    @type bits: int
28    @param bits: Desired bit length of the new key's modulus.
29
30    @rtype: L{tlslite.utils.rsakey.RSAKey}
31    @return: A new RSA private key.
32    """
33    for implementation in implementations:
34        if implementation == "openssl" and cryptomath.m2cryptoLoaded:
35            return OpenSSL_RSAKey.generate(bits)
36        elif implementation == "python":
37            return Python_RSAKey.generate(bits)
38    raise ValueError("No acceptable implementations")
39
40#Parse as an OpenSSL or Python key
41def parsePEMKey(s, private=False, public=False, passwordCallback=None,
42                implementations=["openssl", "python"]):
43    """Parse a PEM-format key.
44
45    The PEM format is used by OpenSSL and other tools.  The
46    format is typically used to store both the public and private
47    components of a key.  For example::
48
49       -----BEGIN RSA PRIVATE KEY-----
50        MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
51        dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
52        dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
53        AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
54        esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
55        gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
56        aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
57        VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
58        CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
59        i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
60        wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
61        6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
62        h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
63        -----END RSA PRIVATE KEY-----
64
65    To generate a key like this with OpenSSL, run::
66
67        openssl genrsa 2048 > key.pem
68
69    This format also supports password-encrypted private keys.  TLS
70    Lite can only handle password-encrypted private keys when OpenSSL
71    and M2Crypto are installed.  In this case, passwordCallback will be
72    invoked to query the user for the password.
73
74    @type s: str
75    @param s: A string containing a PEM-encoded public or private key.
76
77    @type private: bool
78    @param private: If True, a L{SyntaxError} will be raised if the
79    private key component is not present.
80
81    @type public: bool
82    @param public: If True, the private key component (if present) will
83    be discarded, so this function will always return a public key.
84
85    @type passwordCallback: callable
86    @param passwordCallback: This function will be called, with no
87    arguments, if the PEM-encoded private key is password-encrypted.
88    The callback should return the password string.  If the password is
89    incorrect, SyntaxError will be raised.  If no callback is passed
90    and the key is password-encrypted, a prompt will be displayed at
91    the console.
92
93    @rtype: L{tlslite.utils.RSAKey.RSAKey}
94    @return: An RSA key.
95
96    @raise SyntaxError: If the key is not properly formatted.
97    """
98    for implementation in implementations:
99        if implementation == "openssl" and cryptomath.m2cryptoLoaded:
100            key = OpenSSL_RSAKey.parse(s, passwordCallback)
101            break
102        elif implementation == "python":
103            key = Python_RSAKey.parsePEM(s)
104            break
105    else:
106        raise ValueError("No acceptable implementations")
107
108    return _parseKeyHelper(key, private, public)
109
110
111def _parseKeyHelper(key, private, public):
112    if private:
113        if not key.hasPrivateKey():
114            raise SyntaxError("Not a private key!")
115
116    if public:
117        return _createPublicKey(key)
118
119    if private:
120        if hasattr(key, "d"):
121            return _createPrivateKey(key)
122        else:
123            return key
124
125    return key
126
127def parseAsPublicKey(s):
128    """Parse a PEM-formatted public key.
129
130    @type s: str
131    @param s: A string containing a PEM-encoded public or private key.
132
133    @rtype: L{tlslite.utils.rsakey.RSAKey}
134    @return: An RSA public key.
135
136    @raise SyntaxError: If the key is not properly formatted.
137    """
138    return parsePEMKey(s, public=True)
139
140def parsePrivateKey(s):
141    """Parse a PEM-formatted private key.
142
143    @type s: str
144    @param s: A string containing a PEM-encoded private key.
145
146    @rtype: L{tlslite.utils.rsakey.RSAKey}
147    @return: An RSA private key.
148
149    @raise SyntaxError: If the key is not properly formatted.
150    """
151    return parsePEMKey(s, private=True)
152
153def _createPublicKey(key):
154    """
155    Create a new public key.  Discard any private component,
156    and return the most efficient key possible.
157    """
158    if not isinstance(key, RSAKey):
159        raise AssertionError()
160    return _createPublicRSAKey(key.n, key.e)
161
162def _createPrivateKey(key):
163    """
164    Create a new private key.  Return the most efficient key possible.
165    """
166    if not isinstance(key, RSAKey):
167        raise AssertionError()
168    if not key.hasPrivateKey():
169        raise AssertionError()
170    return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP,
171                                key.dQ, key.qInv)
172
173def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto",
174                                                "python"]):
175    for implementation in implementations:
176        if implementation == "openssl" and cryptomath.m2cryptoLoaded:
177            return OpenSSL_RSAKey(n, e)
178        elif implementation == "pycrypto" and cryptomath.pycryptoLoaded:
179            return PyCrypto_RSAKey(n, e)
180        elif implementation == "python":
181            return Python_RSAKey(n, e)
182    raise ValueError("No acceptable implementations")
183
184def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv,
185                        implementations = ["pycrypto", "python"]):
186    for implementation in implementations:
187        if implementation == "pycrypto" and cryptomath.pycryptoLoaded:
188            return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv)
189        elif implementation == "python":
190            return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
191    raise ValueError("No acceptable implementations")
192