]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blobdiff - ctypescrypto/cms.py
Fixed most pylint warning.
[oss/ctypescrypto.git] / ctypescrypto / cms.py
index 68f9c3f229626b9b544f7566b813fac9175be642..bc27e9e34f8d14cd09e63e6343fc8465610ba755 100644 (file)
@@ -10,11 +10,12 @@ create it from raw data and neccessary certificates.
 
 
 """
-from ctypes import c_int, c_void_p, c_char_p, c_int
+from ctypes import c_int, c_void_p, c_char_p, c_int, c_uint, c_size_t, POINTER
 from ctypescrypto.exception import LibCryptoError
 from ctypescrypto import libcrypto
 from ctypescrypto.bio import Membio
 from ctypescrypto.oid import Oid
+from ctypescrypto.x509 import StackOfX509
 
 class CMSError(LibCryptoError):
     """
@@ -24,108 +25,112 @@ class CMSError(LibCryptoError):
 
 class Flags:
     """
-    Constants for flags passed to the CMS methods. 
+    Constants for flags passed to the CMS methods.
     Can be OR-ed together
     """
-    TEXT=1
-    NOCERTS=2
-    NO_CONTENT_VERIFY=4
-    NO_ATTR_VERIFY=8
-    NO_SIGS=NO_CONTENT_VERIFY|NO_ATTR_VERIFY
-    NOINTERN=0x10
-    NO_SIGNER_CERT_VERIFY=0x20
-    NO_VERIFY=0x20
-    DETACHED=0x40
-    BINARY=0x80
-    NOATTR=0x100
-    NOSMIMECAP =0x200
-    NOOLDMIMETYPE=0x400
-    CRLFEOL=0x800
-    STREAM=0x1000
-    NOCRL=0x2000
-    PARTIAL=0x4000
-    REUSE_DIGEST=0x8000
-    USE_KEYID=0x10000
-    DEBUG_DECRYPT=0x20000
+    TEXT = 1
+    NOCERTS = 2
+    NO_CONTENT_VERIFY = 4
+    NO_ATTR_VERIFY = 8
+    NO_SIGS = NO_CONTENT_VERIFY | NO_ATTR_VERIFY
+    NOINTERN = 0x10
+    NO_SIGNER_CERT_VERIFY = 0x20
+    NO_VERIFY = 0x20
+    DETACHED = 0x40
+    BINARY = 0x80
+    NOATTR = 0x100
+    NOSMIMECAP = 0x200
+    NOOLDMIMETYPE = 0x400
+    CRLFEOL = 0x800
+    STREAM = 0x1000
+    NOCRL = 0x2000
+    PARTIAL = 0x4000
+    REUSE_DIGEST = 0x8000
+    USE_KEYID = 0x10000
+    DEBUG_DECRYPT = 0x20000
 
-def CMS(data,format="PEM"):
+def CMS(data, format="PEM"):
     """
     Parses CMS data and returns either SignedData or EnvelopedData
     object
     """
-    b=Membio(data)
+    bio = Membio(data)
     if format == "PEM":
-        ptr=libcrypto.PEM_read_bio_CMS(b.bio,None,None,None)
+        ptr = libcrypto.PEM_read_bio_CMS(bio.bio, None, None, None)
     else:
-        ptr=libcrypto.d2i_CMS_bio(b.bio,None)
+        ptr = libcrypto.d2i_CMS_bio(bio.bio, None)
     typeoid = Oid(libcrypto.OBJ_obj2nid(libcrypto.CMS_get0_type(ptr)))
-    if typeoid.shortname()=="pkcs7-signedData":
+    if typeoid.shortname() == "pkcs7-signedData":
         return SignedData(ptr)
-    elif typeoid.shortname()=="pkcs7-envelopedData":
+    elif typeoid.shortname() == "pkcs7-envelopedData":
         return EnvelopedData(ptr)
-    elif typeoid.shortname()=="pkcs7-encryptedData":
+    elif typeoid.shortname() == "pkcs7-encryptedData":
         return EncryptedData(ptr)
     else:
         raise NotImplementedError("cannot handle "+typeoid.shortname())
 
-class CMSBase(object): 
+class CMSBase(object):
     """
     Common ancessor for all CMS types.
     Implements serializatio/deserialization
     """
-    def __init__(self,ptr=None):
-        self.ptr=ptr
+    def __init__(self, ptr=None):
+        self.ptr = ptr
     def __str__(self):
         """
         Serialize in DER format
         """
-        b=Membio()
-        if not libcrypto.i2d_CMS_bio(b.bio,self.ptr):
+        bio = Membio()
+        if not libcrypto.i2d_CMS_bio(bio.bio, self.ptr):
             raise CMSError("writing CMS to PEM")
-        return str(b)
+        return str(bio)
 
     def pem(self):
         """
         Serialize in PEM format
         """
-        b=Membio()
-        if not libcrypto.PEM_write_bio_CMS(b.bio,self.ptr):
+        bio = Membio()
+        if not libcrypto.PEM_write_bio_CMS(bio.bio, self.ptr):
             raise CMSError("writing CMS to PEM")
-        return str(b)
-        
-    
-        
+        return str(bio)
+
+
+#pylint: disable=R0921
 class SignedData(CMSBase):
+    """
+    Represents signed message (signeddata CMS type)
+    """
     @staticmethod
-    def create(data,cert,pkey,flags=Flags.BINARY,certs=[]):
+    def create(data, cert, pkey, flags=Flags.BINARY, certs=None):
         """
             Creates SignedData message by signing data with pkey and
             certificate.
 
             @param data - data to sign
+            @param cert - signer's certificate
             @param pkey - pkey object with private key to sign
             @param flags - OReed combination of Flags constants
             @param certs - list of X509 objects to include into CMS
         """
         if not pkey.cansign:
             raise ValueError("Specified keypair has no private part")
-        if cert.pubkey!=pkey:
+        if cert.pubkey != pkey:
             raise ValueError("Certificate doesn't match public key")
-        b=Membio(data)
-        if certs is not None and len(certs)>0:
-            certstack=StackOfX509(certs)
+        bio = Membio(data)
+        if certs is not None and len(certs) > 0:
+            certstack = StackOfX509(certs)
         else:
-            certstack=None
-        ptr=libcrypto.CMS_sign(cert.cert,pkey.ptr,certstack,b.bio,flags)
+            certstack = None
+        ptr = libcrypto.CMS_sign(cert.cert, pkey.ptr, certstack, bio.bio, flags)
         if ptr is None:
             raise CMSError("signing message")
         return SignedData(ptr)
-    def sign(self,cert,pkey,md=None,data=None,flags=Flags.BINARY):
+    def sign(self, cert, pkey, digest_type=None, data=None, flags=Flags.BINARY):
         """
             Adds another signer to already signed message
             @param cert - signer's certificate
             @param pkey - signer's private key
-            @param md - message digest to use as DigestType object 
+            @param digest_type - message digest to use as DigestType object
                 (if None - default for key would be used)
             @param data - data to sign (if detached and
                     Flags.REUSE_DIGEST is not specified)
@@ -133,22 +138,21 @@ class SignedData(CMSBase):
         """
         if not pkey.cansign:
             raise ValueError("Specified keypair has no private part")
-        if cert.pubkey!=pkey:
+        if cert.pubkey != pkey:
             raise ValueError("Certificate doesn't match public key")
-        p1=libcrypto.CMS_sign_add1_Signer(self.ptr,cert.cert,pkey.ptr,
-            md.digest,flags)
-        if p1 is None:
+        if libcrypto.CMS_sign_add1_Signer(self.ptr, cert.cert, pkey.ptr,
+                                          digest_type.digest, flags) is None:
             raise CMSError("adding signer")
-        if flags & Flags.REUSE_DIGEST==0:
+        if flags & Flags.REUSE_DIGEST == 0:
             if data is not None:
-                b=Membio(data)
-                biodata=b.bio
+                bio = Membio(data)
+                biodata = bio.bio
             else:
-                biodata=None
-            res= libcrypto.CMS_final(self.ptr,biodata,None,flags)
-            if res<=0:
-                raise CMSError
-    def verify(self,store,flags,data=None,certs=[]):
+                biodata = None
+            res = libcrypto.CMS_final(self.ptr, biodata, None, flags)
+            if res <= 0:
+                raise CMSError("Cannot finalize CMS")
+    def verify(self, store, flags, data=None, certs=None):
         """
         Verifies signature under CMS message using trusted cert store
 
@@ -160,42 +164,47 @@ class SignedData(CMSBase):
                 sertificates to search for signing certificates
         @returns True if signature valid, False otherwise
         """
-        bio=None
-        if data!=None:
-            b=Membio(data)
-            bio=b.bio
-        if certs is not None and len(certs)>0:
-            certstack=StackOfX509(certs)
+        bio = None
+        if data != None:
+            bio_obj = Membio(data)
+            bio = bio_obj.bio
+        if certs is not None and len(certs) > 0:
+            certstack = StackOfX509(certs)
         else:
-            certstack=None
-        res=libcrypto.CMS_verify(self.ptr,certstack,store.store,bio,None,flags)
-        return res>0
-    @property   
+            certstack = None
+        res = libcrypto.CMS_verify(self.ptr, certstack, store.store, bio,
+                                   None, flags)
+        return res > 0
+
+    @property
     def signers(self):
         """
         Return list of signer's certificates
         """
-        p=libcrypto.CMS_get0_signers(self.ptr)
-        if p is None:
-            raise CMSError
-        return StackOfX509(ptr=p,disposable=False)
+        signerlist = libcrypto.CMS_get0_signers(self.ptr)
+        if signerlist is None:
+            raise CMSError("Cannot get signers")
+        return StackOfX509(ptr=signerlist, disposable=False)
+
     @property
     def data(self):
         """
         Returns signed data if present in the message
         """
-        b=Membio()
-        if not libcrypto.CMS_verify(self.ptr,None,None,None,b.bio,Flags.NO_VERIFY):
+        bio = Membio()
+        if not libcrypto.CMS_verify(self.ptr, None, None, None, bio.bio,
+                                    Flags.NO_VERIFY):
             raise CMSError("extract data")
-        return str(b)
-    def addcert(self,cert):
+        return str(bio)
+
+    def addcert(self, cert):
         """
         Adds a certificate (probably intermediate CA) to the SignedData
         structure
         """
-        if libcrypto.CMS_add1_cert(self.ptr,cert.cert)<=0:
-            raise CMSError("adding cert")
-    def addcrl(self,crl):
+        if libcrypto.CMS_add1_cert(self.ptr, cert.cert) <= 0:
+            raise CMSError("Cannot add cert")
+    def addcrl(self, crl):
         """
         Adds a CRL to the signed data structure
         """
@@ -205,10 +214,10 @@ class SignedData(CMSBase):
         """
         List of the certificates contained in the structure
         """
-        p=CMS_get1_certs(self.ptr)
-        if p is None:
+        certstack = libcrypto.CMS_get1_certs(self.ptr)
+        if certstack is None:
             raise CMSError("getting certs")
-        return StackOfX509(ptr=p,disposable=True)
+        return StackOfX509(ptr=certstack, disposable=True)
     @property
     def crls(self):
         """
@@ -217,8 +226,12 @@ class SignedData(CMSBase):
         raise NotImplementedError
 
 class EnvelopedData(CMSBase):
+    """
+    Represents EnvelopedData CMS, i.e. message encrypted with session
+    keys, encrypted with recipient's public keys
+    """
     @staticmethod
-    def create(recipients,data,cipher,flags=0):
+    def create(recipients, data, cipher, flags=0):
         """
         Creates and encrypts message
         @param recipients - list of X509 objects
@@ -226,13 +239,15 @@ class EnvelopedData(CMSBase):
         @param cipher - CipherType object
         @param flags - flag
         """
-        recp=StackOfX509(recipients)
-        b=Membio(data)
-        p=libcrypto.CMS_encrypt(recp.ptr,b.bio,cipher.cipher_type,flags)
-        if p is None:
+        recp = StackOfX509(recipients)
+        bio = Membio(data)
+        cms_ptr = libcrypto.CMS_encrypt(recp.ptr, bio.bio, cipher.cipher_type,
+                                        flags)
+        if cms_ptr is None:
             raise CMSError("encrypt EnvelopedData")
-        return EnvelopedData(p)
-    def decrypt(self,pkey,cert,flags=0):
+        return EnvelopedData(cms_ptr)
+
+    def decrypt(self, pkey, cert, flags=0):
         """
         Decrypts message
         @param pkey - private key to decrypt
@@ -245,15 +260,20 @@ class EnvelopedData(CMSBase):
             raise ValueError("Specified keypair has no private part")
         if pkey != cert.pubkey:
             raise ValueError("Certificate doesn't match private key")
-        b=Membio()
-        res=libcrypto.CMS_decrypt(self.ptr,pkey.ptr,cert.ccert,None,b.bio,flags)
-        if res<=0:
+        bio = Membio()
+        res = libcrypto.CMS_decrypt(self.ptr, pkey.ptr, cert.ccert, None,
+                                    bio.bio, flags)
+        if res <= 0:
             raise CMSError("decrypting CMS")
-        return str(b)
+        return str(bio)
 
 class EncryptedData(CMSBase):
+    """
+    Represents encrypted data CMS structure, i.e. encrypted
+    with symmetric key, shared by sender and recepient.
+    """
     @staticmethod
-    def create(data,cipher,key,flags=0):
+    def create(data, cipher, key, flags=0):
         """
         Creates an EncryptedData message.
         @param data data to encrypt
@@ -262,24 +282,61 @@ class EncryptedData(CMSBase):
         @param key - byte array used as simmetic key
         @param flags - OR-ed combination of Flags constant
         """
-        b=Membio(data)
-        ptr=libcrypto.CMS_EncryptedData_encrypt(b.bio,cipher.cipher_type,key,len(key),flags)
+        bio = Membio(data)
+        ptr = libcrypto.CMS_EncryptedData_encrypt(bio.bio, cipher.cipher_type,
+                                                  key, len(key), flags)
         if ptr is None:
             raise CMSError("encrypt data")
         return EncryptedData(ptr)
-    def decrypt(self,key,flags=0):
+
+    def decrypt(self, key, flags=0):
         """
         Decrypts encrypted data message
         @param key - symmetic key to decrypt
         @param flags - OR-ed combination of Flags constant
         """
-        b=Membio()
-        if libcrypto.CMS_EncryptedData_decrypt(self.ptr,key,len(key),None,
-            b.bio,flags)<=0:
-                raise CMSError("decrypt data")
-        return str(b)
+        bio = Membio()
+        if libcrypto.CMS_EncryptedData_decrypt(self.ptr, key, len(key), None,
+                                               bio.bio, flags) <= 0:
+            raise CMSError("decrypt data")
+        return str(bio)
 
-__all__=['CMS','CMSError','Flags','SignedData','EnvelopedData','EncryptedData']
+__all__ = ['CMS', 'CMSError', 'Flags', 'SignedData', 'EnvelopedData',
+           'EncryptedData']
 
-libcrypto.CMS_verify.restype=c_int
-libcrypto.CMS_verify.argtypes=(c_void_p,c_void_p,c_void_p,c_void_p,c_void_p,c_int)
+libcrypto.CMS_add1_cert.restype = c_int
+libcrypto.CMS_add1_cert.argtypes = (c_void_p, c_void_p)
+libcrypto.CMS_decrypt.restype = c_int
+libcrypto.CMS_decrypt.argtypes = (c_void_p, c_void_p, c_void_p,
+                                  c_void_p, c_void_p, c_uint)
+libcrypto.CMS_encrypt.restype = c_void_p
+libcrypto.CMS_encrypt.argtypes = (c_void_p, c_void_p, c_void_p, c_uint)
+libcrypto.CMS_EncryptedData_decrypt.restype = c_int
+libcrypto.CMS_EncryptedData_decrypt.argtypes = (c_void_p, c_char_p, c_size_t,
+                                                c_void_p, c_void_p, c_uint)
+libcrypto.CMS_EncryptedData_encrypt.restype = c_void_p
+libcrypto.CMS_EncryptedData_encrypt.argtypes = (c_void_p, c_void_p, c_char_p,
+                                                c_size_t, c_uint)
+libcrypto.CMS_final.restype = c_int
+libcrypto.CMS_final.argtypes = (c_void_p, c_void_p, c_void_p, c_uint)
+libcrypto.CMS_get0_signers.restype = c_void_p
+libcrypto.CMS_get0_signers.argtypes = (c_void_p, )
+libcrypto.CMS_get1_certs.restype = c_void_p
+libcrypto.CMS_get1_certs.argtypes = (c_void_p, )
+libcrypto.CMS_sign.restype = c_void_p
+libcrypto.CMS_sign.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p, c_uint)
+libcrypto.CMS_sign_add1_Signer.restype = c_void_p
+libcrypto.CMS_sign_add1_Signer.argtypes = (c_void_p, c_void_p, c_void_p,
+                                           c_void_p, c_uint)
+libcrypto.CMS_verify.restype = c_int
+libcrypto.CMS_verify.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p,
+                                 c_void_p, c_int)
+libcrypto.d2i_CMS_bio.restype = c_void_p
+libcrypto.d2i_CMS_bio.argtypes = (c_void_p, POINTER(c_void_p))
+libcrypto.i2d_CMS_bio.restype = c_int
+libcrypto.i2d_CMS_bio.argtypes = (c_void_p, c_void_p)
+libcrypto.PEM_read_bio_CMS.restype = c_void_p
+libcrypto.PEM_read_bio_CMS.argtypes = (c_void_p, POINTER(c_void_p),
+                                       c_void_p, c_void_p)
+libcrypto.PEM_write_bio_CMS.restype = c_int
+libcrypto.PEM_write_bio_CMS.argtypes = (c_void_p, c_void_p)