]> www.wagner.pp.ru Git - oss/ctypescrypto.git/commitdiff
Merge branch 'master' of https://github.com/vbwagner/ctypescrypto
authorVictor Wagner <vitus@wagner.pp.ru>
Thu, 30 Oct 2014 20:26:14 +0000 (23:26 +0300)
committerVictor Wagner <vitus@wagner.pp.ru>
Thu, 30 Oct 2014 20:26:14 +0000 (23:26 +0300)
README.md
ctypescrypto/cms.py
ctypescrypto/x509.py
tests/testx509.py

index 27991db27b447735a1e444ca4fcd520b18b3b641..87c85d98c8e9334197b23d475a272980ee5231a2 100644 (file)
--- a/README.md
+++ b/README.md
@@ -20,8 +20,8 @@ data structures and groups of functions.
 Digest calculation
 ------------------
 
-Module *ctypescrypto.digest* contain *new()* function which produces
-objects simular to python *hashlib* module objects. 
+Module **ctypescrypto.digest** contain **new()** function which produces
+objects simular to python **hashlib** module objects. 
 
 On the systems where hashlib is linked with libcrypto dynamically,
 hashlib even able to make use of digest types, provided by loadable
@@ -30,6 +30,9 @@ engines.
 This module would utilize same copy of libcrypto library as other
 ctypescrypto modules, so it would work with engine-provided digests.
 
+Additionally there is **DigestType** class which may be needed to
+construct CMS SignedData objects or add signatures to them.
+
 Symmetric ciphers
 -----------------
 
@@ -39,22 +42,30 @@ This object provides methods *update* and *finish* which allows to
 encrypt/decrypt data. All ciphers, supported by your version of OpenSSL
 and its loadable engines are supported.
 
+Additionally the **CipherType** class instances may be used directly to
+pass to other functions such as CMS EnvelopedData or EncryptedData
+**create**
+
 Public key operations
 ---------------------
 
-Module *ctypescrypto.pkey* provides *PKey* object, which represents
+Module **ctypescrypto.pkey** provides **PKey** object, which represents
 public/private key pair or just public key. With this object you can
 sign data, derive shared key and verify signatures.
 
 This is quite low-level object, which can be used to implement some
 non-standard protocols and operations.
 
+Additional module **ctypescrypto.ec** allows to create **PKey** objects
+with elliptic curve keys from just raw secret key as byte buffer or
+python big integer.
+
 X509 certificates
 -----------------
 
-Module *ctypescrypto.x509* contains objects *X509* which represents
+Module **ctypescrypto.x509** contains objects **X509** which represents
 certificate (and can be constructed from string, contained PEM
-or DER certificate) and object *X509Store* which is a store of trusted
+or DER certificate) and object **X509Store** which is a store of trusted
 CA certificates which can be used to high-level signature verifications
 (i.e. in PKCS7/CMS messages).
 
@@ -65,13 +76,43 @@ position of field. Unicode in the names is supported.
 
 There is no support for certificate validity time yet.
 
+**StackOfX509** implements collection of certificates, neccessary for
+some operations with CMS and certificate verification.
+
+CMS documents
+-------------
+
+There is basic constructor function **CMS()**, which parses PEM or der
+representation of cryptographic message and generates appropriate
+object. There are **SignedData**, **EnvelopedData** and
+**EncryptedData** clases. Each class has static method **create**
+allowing to create this subtype of message from raw data and appropriate
+keys and certificates.
+
+**SignedData** has **verify()** method. **EnvelopedData** and
+**EncryptedData** - **decrypt** method.
+
+Unfortunatly, **SignedAndEnvelopedData** seems to be unsupported in
+libcrypto as of version 1.0.1 of OpenSSL.
+
+PBKDF2
+------
+
+Provices interface to password based keyderivation function
+Interface slightly differs from the **hashlib.pbkdf2_hmac** function,
+which have appeared in Python 2.7.8 but functionality is just same,
+although OpenSSL implementation might be faster.
+
+
+
+
 OID database
 ------------
 
 OpenSSL conteins internal object identifiers (OID) database. Each OID
 have apart from dotted-decimal representation long name, short name and
-numeric identifer. Module *ctypescrypto.oid* provides interface to the
-database. *Oid* objects store numeric identifier internally and can
+numeric identifer. Module **ctypescrypto.oid** provides interface to the
+database. **Oid** objects store numeric identifier internally and can
 return both long and short name and dotted-decimal representation.
 
 BIO library
@@ -87,7 +128,7 @@ string or unicode object.
 Exceptions
 ----------
 
-Exceptions, used in the *ctypescrypto* to report problems are tied
+Exceptions, used in the **ctypescrypto** to report problems are tied
 closely with OpenSSL error-reporting functions, so if such an exception
 occurs, as much as possibly information from inside libcrypto would be
 available in the Python
@@ -95,8 +136,12 @@ available in the Python
 Engine support
 --------------
 
-There is just one function *ctypescrypt.engine.set_default*. which loads 
+There is just one function **ctypescrypt.engine.set_default**. which loads 
 specified engine by id and makes it default for all algorithms,
 supported by it. It is enough for me to use Russian national
-cryptographic algoritms, provided by *gost* engine.
+cryptographic algoritms, provided by **gost** engine.
+
+Test Suite
+----------
 
+Test suite is fairly incomplete. Contributions are welcome.
index 9defb1d5b5c1403b1b6c16e6f4b9d8ebc76f71b4..2c038985aba8ae9488f37083115dc5dd69bb4e6b 100644 (file)
@@ -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,30 +63,60 @@ 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):
+       def create(data,cert,pkey,flags=Flags.BINARY,certs=[]):
                """
                        Creates SignedData message by signing data with pkey and
                        certificate.
 
                        @param data - data to sign
                        @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:
                        raise ValueError("Certificate doesn't match public key")
                b=Membio(data)
-               ptr=libcrypto.CMS_sign(cert.cert,pkey.ptr,None,b.bio,flags)
+               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)
                if ptr is None:
                        raise CMSError("signing message")
                return SignedData(ptr)
@@ -94,10 +125,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")
@@ -116,49 +148,53 @@ class SignedData:
                        res= libcrypto.CMS_final(self.ptr,biodata,None,flags)
                        if res<=0:
                                raise CMSError
-       def verify(self,store,flags,data=None):
+       def verify(self,store,flags,data=None,certs=[]):
+               """
+               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
+               param certs - list of certificates to use during verification
+                               If Flags.NOINTERN is specified, these are only
+                               sertificates to search for signing certificates
+               @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)
+               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
-       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):
                """
                Return list of signer's certificates
                """
-               raise NotImplementedError
+               p=libcrypto.CMS_get0_signers(self.ptr)
+               if p is None:
+                       raise CMSError
+               return StackOfX509(ptr=p,disposable=False)
        @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
                structure
                """
-               raise NotImplementedError
+               if libcrypto.CMS_add1_cert(self.ptr,cert.cert)<=0:
+                       raise CMSError("adding cert")
        def addcrl(self,crl):
                """
                Adds a CRL to the signed data structure
@@ -169,7 +205,10 @@ class SignedData:
                """
                List of the certificates contained in the structure
                """
-               raise NotImplementedError
+               p=CMS_get1_certs(self.ptr)
+               if p is None:
+                       raise CMSError("getting certs")
+               return StackOfX509(ptr=p,disposable=True)
        @property
        def crls(self):
                """
@@ -177,29 +216,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):
                """
@@ -209,8 +226,12 @@ class EnvelopedData:
                @param cipher - CipherType object
                @param flags - flag
                """
-               # Need to be able to handle OPENSSL stacks
-               raise NotImplementedError       
+               recp=StackOfX509(recipients)
+               b=Membio(data)
+               p=libcrypto.CMS_encrypt(recp.ptr,b.bio,cipher.cipher_type,flags)
+               if p is None:
+                       raise CMSError("encrypt EnvelopedData")
+               return EnvelopedData(p)
        def decrypt(self,pkey,cert,flags=0):
                """
                Decrypts message
@@ -229,3 +250,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)
index 5d5d448770a887ff0622d6adddc9b5d7e1c0eeeb..5c2a50d99303392a483243dc3e7db7647b5ab6b3 100644 (file)
@@ -1,10 +1,9 @@
-from ctypes import c_void_p,create_string_buffer,c_long,c_int
+from ctypes import c_void_p,create_string_buffer,c_long,c_int,POINTER,c_char_p
 from ctypescrypto.bio import Membio
 from ctypescrypto.pkey import PKey
 from ctypescrypto.oid import Oid
 from ctypescrypto.exception import LibCryptoError
 from ctypescrypto import libcrypto
-
 class X509Error(LibCryptoError):
        """
        Exception, generated when some openssl function fail
@@ -163,13 +162,17 @@ class X509:
        def pubkey(self):
                """EVP PKEy object of certificate public key"""
                return PKey(ptr=libcrypto.X509_get_pubkey(self.cert,False))
-       def verify(self,store=None,key=None):   
+       def verify(self,store=None,chain=[],key=None):  
                """ 
                Verify self. Supports verification on both X509 store object 
                or just public issuer key
                @param store X509Store object.
+               @param chain - list of X509 objects to add into verification
+                       context.These objects are untrusted, but can be used to
+                       build certificate chain up to trusted object in the store
                @param key - PKey object
-               parameters are mutually exclusive. If neither is specified, attempts to verify
+               parameters stora and key are mutually exclusive. If neither is specified, attempts to verify
+               
                itself as self-signed certificate
                """
                if store is not None and key is not None:
@@ -178,7 +181,11 @@ class X509:
                        ctx=libcrypto.X509_STORE_CTX_new()
                        if ctx is None:
                                raise X509Error("Error allocating X509_STORE_CTX")
-                       if libcrypto.X509_STORE_CTX_init(ctx,store.ptr,self.cert,None) < 0:
+                       if chain is not None and len(chain)>0:
+                               ch=StackOfX509(chain)
+                       else:
+                               ch=None
+                       if libcrypto.X509_STORE_CTX_init(ctx,store.store,self.cert,ch) < 0:
                                raise X509Error("Error allocating X509_STORE_CTX")
                        res= libcrypto.X509_verify_cert(ctx)
                        libcrypto.X509_STORE_CTX_free(ctx)
@@ -243,21 +250,22 @@ class X509Store:
                # Todo - set verification flags
                # 
                self.store=libcrypto.X509_STORE_new()
+               if self.store is None:
+                       raise X509Error("allocating store")
                lookup=libcrypto.X509_STORE_add_lookup(self.store,libcrypto.X509_LOOKUP_file())
                if lookup is None:
                        raise X509Error("error installing file lookup method")
                if (file is not None):
-                       if not libcrypto.X509_LOOKUP_loadfile(lookup,file,1):
+                       if not libcrypto.X509_LOOKUP_ctrl(lookup,1,file,1,None)>0:
                                raise X509Error("error loading trusted certs from file "+file)
-               
                lookup=libcrypto.X509_STORE_add_lookup(self.store,libcrypto.X509_LOOKUP_hash_dir())
                if lookup is None:
                        raise X509Error("error installing hashed lookup method")
                if dir is not None:
-                       if not libcrypto.X509_LOOKUP_add_dir(lookup,dir,1):
+                       if not libcrypto.X509_LOOKUP_ctrl(lookup,2,dir,1,None)>0:
                                raise X509Error("error adding hashed  trusted certs dir "+dir)
                if default:
-                       if not libcrypto.X509_LOOKUP.add_dir(lookup,None,3):
+                       if not libcrypto.X509_LOOKUP_ctrl(lookup,2,None,3,None)>0:
                                raise X509Error("error adding default trusted certs dir ")
        def add_cert(self,cert):
                """
@@ -293,6 +301,75 @@ class X509Store:
                        purp_no = purpose
                if libcrypto.X509_STORE_set_purpose(self.store,purp_no)<=0:
                        raise X509Error("cannot set purpose")
+       def setdepth(self,depth):
+               libcrypto.X509_STORE_set_depth(self.store,depth)
+       def settime(self, time):
+               """
+               Set point in time used to check validity of certificates for
+               """
+               if isinstance(time,datetime.datetime) or isinstance(time,datetime.date):
+                       d=int(time.strftime("%s"))
+               elif isinstance(time,int):
+                       pass
+               else:
+                       raise TypeError("datetime.date, datetime.datetime or integer is required as time argument")
+               raise NotImplementedError
+class StackOfX509:
+       """
+       Implements OpenSSL STACK_OF(X509) object.
+       It looks much like python container types
+       """
+       def __init__(self,certs=None,ptr=None,disposable=True):
+               """
+               Create stack
+               @param certs - list of X509 objects. If specified, read-write
+                       stack is created and populated by these certificates
+               @param ptr - pointer to OpenSSL STACK_OF(X509) as returned by
+                       some functions
+               @param disposable - if True, stack created from object, returned
+                               by function is copy, and can be modified and need to be
+                               freeid. If false, it is just pointer into another
+                               structure i.e. CMS_ContentInfo
+               """
+               if  ptr is None:
+                       self.need_free = True
+                       self.ptr=libcrypt.sk_new_null()
+                       if certs is not None:
+                               for crt in certs:
+                                       self.append(crt)
+               elif not certs is None:
+                               raise ValueError("cannot handle certs an ptr simultaneously")
+               else:
+                       self.need_free = disposable
+                       self.ptr=ptr
+       def __len__(self):
+               return libcrypto.sk_num(self.ptr)
+       def __getitem__(self,index):
+               if index <0 or index>=len(self):
+                       raise IndexError
+               p=libcrypto.sk_value(self.ptr,index)
+               return X509(ptr=libcrypto.X509_dup(p))
+       def __putitem__(self,index,value):
+               if not self.need_free:
+                       raise ValueError("Stack is read-only")
+               if index <0 or index>=len(self):
+                       raise IndexError
+               p=libcrypto.sk_set(self.ptr,index,libcrypto.X509_dup(value.cert))
+               libcrypto.X509_free(p)
+       def __delitem__(self,index):    
+               if not self.need_free:
+                       raise ValueError("Stack is read-only")
+               if index <0 or index>=len(self):
+                       raise IndexError
+               p=libcrypto.sk_delete(self.ptr,index)
+               libcrypto.X509_free(p)
+       def __del__(self):
+               if self.need_free:
+                       libcrypto.sk_pop_free(self.ptr,libcrypto.X509_free)
+       def append(self,value):
+               if not self.need_free:
+                       raise ValueError("Stack is read-only")
+               libcrypto.sk_push(self.ptr,libcrypto.X509_dup(value.cert))
 libcrypto.i2a_ASN1_INTEGER.argtypes=(c_void_p,c_void_p)
 libcrypto.ASN1_STRING_print_ex.argtypes=(c_void_p,c_void_p,c_long)
 libcrypto.X509_get_serialNumber.argtypes=(c_void_p,)
@@ -302,3 +379,10 @@ libcrypto.X509_NAME_ENTRY_get_object.argtypes=(c_void_p,)
 libcrypto.OBJ_obj2nid.argtypes=(c_void_p,)
 libcrypto.X509_NAME_get_entry.restype=c_void_p
 libcrypto.X509_NAME_get_entry.argtypes=(c_void_p,c_int)
+libcrypto.X509_STORE_new.restype=c_void_p
+libcrypto.X509_STORE_add_lookup.restype=c_void_p
+libcrypto.X509_STORE_add_lookup.argtypes=(c_void_p,c_void_p)
+libcrypto.X509_LOOKUP_file.restype=c_void_p
+libcrypto.X509_LOOKUP_hash_dir.restype=c_void_p
+libcrypto.X509_LOOKUP_ctrl.restype=c_int
+libcrypto.X509_LOOKUP_ctrl.argtypes=(c_void_p,c_int,c_char_p,c_long,POINTER(c_char_p))
index 65b4a7a09df80a0b2526babdba2f4972f756b656..2a09e78b562b869a8deea528333d34ab4126fbf5 100644 (file)
@@ -3,6 +3,7 @@
 
 from ctypescrypto.x509 import X509,X509Store
 from ctypescrypto.oid import Oid
+from tempfile import NamedTemporaryFile
 import unittest
 
 
@@ -67,6 +68,47 @@ WSaUuftL/+yFk729xDoYkOZhFwUSUM5SbEZ0JpufWFjDi3Qwj3ZOTXliHC3e4C71
 iFTXJP8/Au8kfezlA4b+eS81zWq2BFvNlBQsgf04S88oew0CuBBgtjUIIw7XZkS0
 3QIDAQAB
 -----END PUBLIC KEY-----
+"""
+       digicert_cert="""digicert.crt
+-----BEGIN CERTIFICATE-----
+MIIG5jCCBc6gAwIBAgIQAze5KDR8YKauxa2xIX84YDANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA3MTEwOTEyMDAwMFoXDTIxMTExMDAwMDAwMFowaTEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTEoMCYGA1UEAxMfRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPOWYth1bhn/
+PzR8SU8xfg0ETpmB4rOFVZEwscCvcLssqOcYqj9495BoUoYBiJfiOwZlkKq9ZXbC
+7L4QWzd4g2B1Rca9dKq2n6Q6AVAXxDlpufFP74LByvNK28yeUE9NQKM6kOeGZrzw
+PnYoTNF1gJ5qNRQ1A57bDIzCKK1Qss72kaPDpQpYSfZ1RGy6+c7pqzoC4E3zrOJ6
+4GAiBTyC01Li85xH+DvYskuTVkq/cKs+6WjIHY9YHSpNXic9rQpZL1oRIEDZaARo
+LfTAhAsKG3jf7RpY3PtBWm1r8u0c7lwytlzs16YDMqbo3rcoJ1mIgP97rYlY1R4U
+pPKwcNSgPqcCAwEAAaOCA4UwggOBMA4GA1UdDwEB/wQEAwIBhjA7BgNVHSUENDAy
+BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUH
+AwgwggHEBgNVHSAEggG7MIIBtzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUH
+AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o
+dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0
+AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1
+AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp
+AGcAaQBDAGUAcgB0ACAARQBWACAAQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl
+AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo
+AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg
+AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg
+AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wEgYDVR0TAQH/BAgwBgEB/wIBADCB
+gwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
+dC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NBQ2Vy
+dHMvRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0MIGPBgNVHR8EgYcw
+gYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hB
+c3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0
+LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwHQYDVR0OBBYE
+FExYyyXwQU9S9CjIgUObpqig5pLlMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoI
+Au9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQBMeheHKF0XvLIyc7/NLvVYMR3wsXFU
+nNabZ5PbLwM+Fm8eA8lThKNWYB54lBuiqG+jpItSkdfdXJW777UWSemlQk808kf/
+roF/E1S3IMRwFcuBCoHLdFfcnN8kpCkMGPAc5K4HM+zxST5Vz25PDVR708noFUjU
+xbvcNRx3RQdIRYW9135TuMAW2ZXNi419yWBP0aKb49Aw1rRzNubS+QOy46T15bg+
+BEkAui6mSnKDcp33C4ypieez12Qf1uNgywPE3IjpnSUBAHHLA7QpYCWP+UbRe3Gu
+zVMSW4SOwg/H7ZMZ2cn6j1g0djIvruFQFGHUqFijyDATI+/GJYw2jxyA
+-----END CERTIFICATE-----
 """
        def test_readpubkey(self):
                c=X509(self.cert1)
@@ -104,7 +146,31 @@ iFTXJP8/Au8kfezlA4b+eS81zWq2BFvNlBQsgf04S88oew0CuBBgtjUIIw7XZkS0
                pk2=c.pubkey
                self.assertFalse(c.verify(key=pk2))
                self.assertTrue(c.verify(key=pubkey))
+       def test_default_filestore(self):
+               store=X509Store(default=True)
+               c1=X509(self.cert1)
+               # Cert signed by our CA shouldn't be successfully verified
+               # by default CA store
+               self.assertFalse(c1.verify(store))
+               # but cert, downloaded from some commercial CA - should.
+               c2=X509(self.digicert_cert)
+               self.assertTrue(c2.verify(store))
        def test_verify_by_filestore(self):
+               trusted=NamedTemporaryFile()
+               trusted.write(self.ca_cert)
+               trusted.flush()
+               goodcert=X509(self.cert1)
+               badcert=X509(self.cert1[0:-30]+"GG"+self.cert1[-28:])
+               gitcert=X509(self.digicert_cert)
+               store=X509Store(file=trusted.name)
+               # We should successfuly verify certificate signed by our CA cert
+               self.assertTrue(goodcert.verify(store))
+               # We should reject corrupted certificate
+               self.assertFalse(badcert.verify(store))
+               # And if we specify explicitely certificate file, certificate,
+               # signed by some commercial CA should be rejected too
+               self.assertFalse(gitcert.verify(store))
+               trusted.close()
                pass
        def test_verify_by_dirstore(self):
                pass