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
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
-----------------
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).
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
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
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.
"""
-
+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
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)
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")
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
"""
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):
"""
"""
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):
"""
@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
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)
-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
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:
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)
# 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):
"""
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,)
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))
from ctypescrypto.x509 import X509,X509Store
from ctypescrypto.oid import Oid
+from tempfile import NamedTemporaryFile
import unittest
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)
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