From 1dccf4b415022f7155d24132cc71e1826fedc359 Mon Sep 17 00:00:00 2001 From: Victor Wagner Date: Mon, 27 Oct 2014 13:04:21 +0300 Subject: [PATCH] CMS verification implemented --- ctypescrypto/cms.py | 134 +++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 52 deletions(-) diff --git a/ctypescrypto/cms.py b/ctypescrypto/cms.py index 9defb1d..f1a4dbb 100644 --- a/ctypescrypto/cms.py +++ b/ctypescrypto/cms.py @@ -10,8 +10,9 @@ create it from raw data and neccessary certificates. """ - +from ctypes import c_int, c_void_p, c_char_p, c_int from ctypescrypto.exception import LibCryptoError +from ctypescrypto import libcrypto from ctypescrypto.bio import Membio from ctypescrypto.oid import Oid @@ -62,15 +63,39 @@ def CMS(data,format="PEM"): return SignedData(ptr) elif typeoid.shortname()=="pkcs7-envelopedData": return EnvelopedData(ptr) + elif typeoid.shortname()=="pkcs7-encryptedData": + return EncryptedData(ptr) else: raise NotImplementedError("cannot handle "+typeoid.shortname()) +class CMSBase: + """ + Common ancessor for all CMS types. + Implements serializatio/deserialization + """ + 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): + raise CMSError("writing CMS to PEM") + return str(b) + def pem(self): + """ + Serialize in PEM format + """ + b=Membio() + if not libcrypto.PEM_write_bio_CMS(b.bio,self.ptr): + raise CMSError("writing CMS to PEM") + return str(b) + -class SignedData: - def __init__(self,ptr=None): - self.ptr=ptr +class SignedData(CMSBase): @staticmethod def create(data,cert,pkey,flags=Flags.BINARY): """ @@ -94,10 +119,11 @@ class SignedData: Adds another signer to already signed message @param cert - signer's certificate @param pkey - signer's private key - @param data - data to sign (if detached) - @param md - message digest to use as DigestType object (if None - default for key - would be used) - @param flags - flags + @param md - 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) + @param flags - ORed combination of Flags consants """ if not pkey.cansign: raise ValueError("Specified keypair has no private part") @@ -117,30 +143,20 @@ class SignedData: if res<=0: raise CMSError def verify(self,store,flags,data=None): + """ + Verifies signature under CMS message using trusted cert store + + @param store - X509Store object with trusted certs + @param flags - OR-ed combination of flag consants + @param data - message data, if messge has detached signature + @returns True if signature valid, False otherwise + """ bio=None if data!=None: b=Membio(data) bio=b.bio - res=libcrypto.CMS_verify(self.ptr,store.store,bio,None,flags) + res=libcrypto.CMS_verify(self.ptr,None,store.store,bio,None,flags) return res>0 - def __str__(self): - """ - Serialize in DER format - """ - b=Membio() - if not libcrypto.i2d_CMS_bio(b.bio,self.ptr): - raise CMSError("writing CMS to PEM") - return str(b) - - def pem(self): - """ - Serialize in PEM format - """ - b=Membio() - if not libcrypto.PEM_write_bio_CMS(b.bio,self.ptr): - raise CMSError("writing CMS to PEM") - return str(b) - @property def signers(self,store=None): """ @@ -150,9 +166,12 @@ class SignedData: @property def data(self): """ - Returns signed data if present + Returns signed data if present in the message """ - raise NotImplementedError + b=Membio() + if not libcrypto.CMS_verify(self.ptr,None,None,None,b.bio,Flags.NO_VERIFY): + raise CMSError("extract data") + return str(b) def addcert(self,cert): """ Adds a certificate (probably intermediate CA) to the SignedData @@ -177,29 +196,7 @@ class SignedData: """ raise NotImplementedError -class EnvelopedData: - def __init__(self,ptr): - """ - Initializes an object. For internal use - """ - self.ptr=ptr - def __str__(self): - """ - Serialize in DER format - """ - b=Membio() - if not libcrypto.i2d_CMS_bio(b.bio,self.ptr): - raise CMSError("writing CMS to PEM") - return str(b) - - def pem(self): - """ - Serialize in PEM format - """ - b=Membio() - if not libcrypto.PEM_write_bio_CMS(b.bio,self.ptr): - raise CMSError("writing CMS to PEM") - return str(b) +class EnvelopedData(CMSBase): @staticmethod def create(recipients,data,cipher,flags=0): """ @@ -229,3 +226,36 @@ class EnvelopedData: if res<=0: raise CMSError("decrypting CMS") return str(b) + +class EncryptedData(CMSBase): + @staticmethod + def create(data,cipher,key,flags=0): + """ + Creates an EncryptedData message. + @param data data to encrypt + @param cipher cipher.CipherType object represening required + cipher type + @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) + if ptr is None: + raise CMSError("encrypt data") + return EncryptedData(ptr) + 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) + + + +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) -- 2.39.2