1. Sybren Stüvel
  2. python-rsa

Commits

Sybren Stüvel  committed c07a41e

Added support for loading public keys from OpenSSL

  • Participants
  • Parent commits 4365d45
  • Branches default

Comments (0)

Files changed (3)

File .pydevproject

View file
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?eclipse-pydev version="1.0"?>
-
-<pydev_project>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
-<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
-<path>/python-rsa</path>
-</pydev_pathproperty>
-</pydev_project>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/python-rsa</path>
+</pydev_pathproperty>
+<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
+<path>C:\cygwin\home\Sybren\python-rsa-venv-py27\Lib\site-packages\pyasn1-0.1.3-py2.7.egg</path>
+</pydev_pathproperty>
+</pydev_project>

File rsa/asn1.py

View file
+'''ASN.1 definitions.
+
+Not all ASN.1-handling code use these definitions, but when it does, they should be here.
+'''
+
+from pyasn1.type import univ, namedtype, tag
+
+class PubKeyHeader(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('oid', univ.ObjectIdentifier()),
+        namedtype.NamedType('parameters', univ.Null()),
+    )
+
+class OpenSSLPubKey(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('header', PubKeyHeader()),
+        
+        # This little hack (the implicit tag) allows us to get a Bit String as Octet String
+        namedtype.NamedType('key', univ.OctetString().subtype(
+                                          implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3))),
+    )
+
+
+class AsnPubKey(univ.Sequence):
+    '''ASN.1 contents of DER encoded public key:
+    
+    RSAPublicKey ::= SEQUENCE {
+         modulus           INTEGER,  -- n
+         publicExponent    INTEGER,  -- e
+    '''
+
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('modulus', univ.Integer()),
+        namedtype.NamedType('publicExponent', univ.Integer()),
+    )

File rsa/key.py

View file
 '''
 
 import logging
-from rsa._compat import b
+from rsa._compat import b, bytes_type
 
 import rsa.prime
 import rsa.pem
 
 log = logging.getLogger(__name__)
 
+
+
 class AbstractKey(object):
     '''Abstract superclass for private and public keys.'''
 
         '''
 
         from pyasn1.codec.der import decoder
-        (priv, _) = decoder.decode(keyfile)
-
-        # ASN.1 contents of DER encoded public key:
-        #
-        # RSAPublicKey ::= SEQUENCE {
-        #     modulus           INTEGER,  -- n
-        #     publicExponent    INTEGER,  -- e
-
-        as_ints = tuple(int(x) for x in priv)
-        return cls(*as_ints)
+        from rsa.asn1 import AsnPubKey
+        
+        (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
+        return cls(n=priv['modulus'], e=priv['publicExponent'])
 
     def _save_pkcs1_der(self):
         '''Saves the public key in PKCS#1 DER format.
         @returns: the DER-encoded public key.
         '''
 
-        from pyasn1.type import univ, namedtype
         from pyasn1.codec.der import encoder
-
-        class AsnPubKey(univ.Sequence):
-            componentType = namedtype.NamedTypes(
-                namedtype.NamedType('modulus', univ.Integer()),
-                namedtype.NamedType('publicExponent', univ.Integer()),
-            )
+        from rsa.asn1 import AsnPubKey
 
         # Create the ASN object
         asn_key = AsnPubKey()
         der = self._save_pkcs1_der()
         return rsa.pem.save_pem(der, 'RSA PUBLIC KEY')
 
+    @classmethod
+    def load_pkcs1_openssl_pem(cls, keyfile):
+        '''Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL.
+        
+        These files can be recognised in that they start with BEGIN PUBLIC KEY
+        rather than BEGIN RSA PUBLIC KEY.
+        
+        The contents of the file before the "-----BEGIN PUBLIC KEY-----" and
+        after the "-----END PUBLIC KEY-----" lines is ignored.
+
+        @param keyfile: contents of a PEM-encoded file that contains the public
+            key, from OpenSSL.
+        @return: a PublicKey object
+        '''
+
+        der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY')
+        return cls.load_pkcs1_openssl_der(der)
+
+    @classmethod
+    def load_pkcs1_openssl_der(cls, keyfile):
+        '''Loads a PKCS#1 DER-encoded public key file from OpenSSL.
+
+        @param keyfile: contents of a DER-encoded file that contains the public
+            key, from OpenSSL.
+        @return: a PublicKey object
+        '''
+    
+        from rsa.asn1 import OpenSSLPubKey
+        from pyasn1.codec.der import decoder
+        from pyasn1.type import univ
+        
+        (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
+        
+        if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'):
+            raise TypeError("This is not a DER-encoded OpenSSL-compatible public key")
+                
+        return cls._load_pkcs1_der(keyinfo['key'][1:])
+        
+        
+
+
 class PrivateKey(AbstractKey):
     '''Represents a private RSA key.