]> www.wagner.pp.ru Git - oss/ctypescrypto.git/commitdiff
Merge branch 'master' of https://github.com/vbwagner/ctypescrypto
authorVictor Wagner <vitus@wagner.pp.ru>
Sat, 20 Dec 2014 07:13:35 +0000 (10:13 +0300)
committerVictor Wagner <vitus@wagner.pp.ru>
Sat, 20 Dec 2014 07:13:35 +0000 (10:13 +0300)
merged uncommited exception syntax changes

15 files changed:
ctypescrypto/__init__.py
ctypescrypto/bio.py
ctypescrypto/cipher.py
ctypescrypto/cms.py
ctypescrypto/digest.py
ctypescrypto/ec.py
ctypescrypto/engine.py
ctypescrypto/exception.py
ctypescrypto/oid.py
ctypescrypto/pbkdf2.py
ctypescrypto/pkey.py
ctypescrypto/rand.py
ctypescrypto/x509.py
setup.py
tests/testx509.py

index 27ad0c50b8a9efa0f91a851a7381e83cb9f7a809..ebf8c41a7750e6c9dd3a2bc31976c4df65270489 100644 (file)
@@ -3,6 +3,7 @@
 
 """
 
+
 from ctypes import CDLL,c_char_p
 
 def config(filename=None):
@@ -12,6 +13,8 @@ def config(filename=None):
        """
        libcrypto.OPENSSL_config(filename)
 
+__all__ = ['bio','cipher','cms','config','digest','ec','engine','exception','oid','pbkdf2','pkey','rand','x509']
+
 libcrypto = CDLL("libcrypto.so.1.0.0")
 libcrypto.OPENSSL_config.argtypes=(c_char_p,)
 libcrypto.OPENSSL_add_all_algorithms_conf()
index a33310572cdc54213a70c10881044e0bce0c6fc9..ae89aa3bac354b9e934002b3c40e2c1820fec96f 100644 (file)
@@ -83,6 +83,8 @@ class Membio:
                Resets the read-only bio to start and discards all data from writable bio
                """
                libcrypto.BIO_ctrl(self.bio,1,0,None)
+
+__all__ = ['Membio']
 libcrypto.BIO_s_mem.restype=c_void_p
 libcrypto.BIO_new.restype=c_void_p
 libcrypto.BIO_new.argtypes=(c_void_p,)
index 367f2b937767a742d2a74b7cc1d2d501a303a722..332272570f824c9830dbe003a09c123f138b5aa7 100644 (file)
@@ -12,6 +12,8 @@ CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")
 
 #
 
+__all__ = ['CipherError','new','Cipher','CipherType']
+
 class CipherError(LibCryptoError):
        pass
 
index 2c038985aba8ae9488f37083115dc5dd69bb4e6b..9213d27b8ff5390ce0aa38881900b8d8a25dd42f 100644 (file)
@@ -279,7 +279,7 @@ class EncryptedData(CMSBase):
                                raise CMSError("decrypt data")
                return str(b)
 
-               
+__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)
index 5eeeaee68757614285fb8580484b32e0f0fc2913..26b46bd7337e5bbd467a8252ec29514775a5edd9 100644 (file)
@@ -19,6 +19,7 @@ from ctypescrypto.exception import LibCryptoError
 from ctypescrypto.oid import Oid\r
 DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")\r
 \r
+__all__ = ['DigestError','Digest','DigestType','new']\r
 \r
 class DigestError(LibCryptoError):\r
        pass\r
index f3ea77831a718a652a3902918acc977ec0b2586a..047aad97a1d6db7225d8f6b5c967647df364ba22 100644 (file)
@@ -5,6 +5,8 @@ from ctypescrypto.pkey import PKey, PKeyError
 from ctypes import c_void_p,c_char_p,c_int,byref
 from ctypescrypto import libcrypto
 
+__all__ = [ 'create']
+
 def create(curve,data):
        """
                Creates EC keypair from the just secret key and curve name
index dd7c0281b34a255670d55ab868322128b10a3d93..898b20dc4c0268f687a443373dc569e5fe06ec5c 100644 (file)
@@ -4,6 +4,9 @@ engine loading and configuration
 from ctypes import *
 from ctypescrypto import libcrypto
 from ctypescrypto.exception import LibCryptoError
+
+__all__=['default','set_default']
+
 default=None
 
 def set_default(engine):
index c4710eca32742a817bfb1204a0d7550bcce8d433..43ba6a0b5a8858402f5fc0902d5b596bb54f1bdb 100644 (file)
@@ -4,6 +4,9 @@ Exception which extracts libcrypto error information
 from ctypes import *
 from ctypescrypto import libcrypto
 strings_loaded=False
+
+__all__ = ['LibCryptoError','clear_err_stack']
+
 class LibCryptoError(Exception):
        """
                Exception for libcrypto errors. Adds all the info, which can be
index 976cd3f8e5b7cf07cc6ab86e93e1400d4acac52d..7d4fc21439206c0d196239755f6a2874ea9c9a4c 100644 (file)
@@ -9,6 +9,9 @@
 """
 from ctypescrypto import libcrypto
 from ctypes import c_char_p, c_void_p, c_int, create_string_buffer
+
+__all__ = ['Oid','create','cleanup']
+
 class Oid:
        """
                Represents an OID. It can be consturucted by textual
index 0c2b077f175804048e268c918de3d180fff72313..c2e01bbe95de7e8dc5a53d31801e40366cd40ec3 100644 (file)
@@ -7,6 +7,8 @@ from ctypes import c_char_p,c_int, c_void_p, create_string_buffer
 from ctypescrypto import libcrypto
 from ctypescrypto.digest import DigestType
 
+__all__ = ['pbkdf2']
+
 def pbkdf2(password,salt,outlen,digesttype="sha1",iterations=2000):
        """
                Interface to PKCS5_PBKDF2_HMAC function
index 10366ee0b318e1947b4448a1be4f9419884af5b3..59a53486f9f62e877cf1748fc5e6c83f5f15a063 100644 (file)
@@ -10,6 +10,8 @@ from ctypescrypto import libcrypto
 from ctypescrypto.exception import LibCryptoError,clear_err_stack
 from ctypescrypto.bio import Membio
 import sys
+
+__all__ = ['PKeyError','password_callback','PKey']
 class PKeyError(LibCryptoError):
        pass
 
index f14c6f769836d76126b402c628829b46d9548b3d..4cc86e297fe0151264c517133a96b4c32822aa10 100644 (file)
@@ -6,6 +6,8 @@ from ctypes import create_string_buffer, c_char_p, c_int, c_double
 from ctypescrypto import libcrypto
 from ctypescrypto.exception import LibCryptoError
 
+__all__ = ['RandError','bytes','pseudo_bytes','seed','status']
+
 class RandError(LibCryptoError):
        pass
 
index 5c2a50d99303392a483243dc3e7db7647b5ab6b3..bd056d32f6227bcba4593e26fd79d06504ee5097 100644 (file)
@@ -1,9 +1,78 @@
-from ctypes import c_void_p,create_string_buffer,c_long,c_int,POINTER,c_char_p
+"""
+Implements interface to openssl X509 and X509Store structures, 
+I.e allows to load, analyze and verify certificates.
+
+X509Store objects are also used to verify other signed documets,
+such as CMS, OCSP and timestamps.
+"""
+
+
+
+from ctypes import c_void_p,create_string_buffer,c_long,c_int,POINTER,c_char_p,Structure,cast
 from ctypescrypto.bio import Membio
 from ctypescrypto.pkey import PKey
 from ctypescrypto.oid import Oid
 from ctypescrypto.exception import LibCryptoError
 from ctypescrypto import libcrypto
+from datetime import datetime
+try:
+       from pytz import utc
+except ImportError:
+       from datetime import timedelta
+       ZERO=timedelta(0)
+       class UTC(datetime.tzinfo):
+               """tzinfo object for UTC. 
+                       If no pytz is available, we would use it.
+               """
+
+               def utcoffset(self, dt):
+                       return ZERO
+
+               def tzname(self, dt):
+                       return "UTC"
+
+               def dst(self, dt):
+                       return ZERO
+
+       utc=UTC()
+
+__all__ = ['X509Error','X509Name','X509Store','StackOfX509']
+
+class _validity(Structure):
+       """ ctypes representation of X509_VAL structure 
+               needed to access certificate validity period, because openssl
+               doesn't provide fuctions for it - only macros
+       """
+       _fields_ =      [('notBefore',c_void_p),('notAfter',c_void_p)]
+
+class _cinf(Structure):
+       """ ctypes representtion of X509_CINF structure 
+           neede to access certificate data, which are accessable only
+               via macros
+       """
+       _fields_ = [('version',c_void_p),
+               ('serialNumber',c_void_p),
+               ('sign_alg',c_void_p),
+               ('issuer',c_void_p),
+               ('validity',POINTER(_validity)),
+               ('subject',c_void_p),
+               ('pubkey',c_void_p),
+               ]
+
+class _x509(Structure):
+       """
+       ctypes represntation of X509 structure needed
+       to access certificate data which are accesable only via
+       macros, not functions
+       """
+       _fields_ = [('cert_info',POINTER(_cinf)),
+                               ('sig_alg',c_void_p),
+                               ('signature',c_void_p),
+                               # There are a lot of parsed extension fields there
+                               ]
+_px509 = POINTER(_x509)
+
+# X509_extlist is not exported yet, because is not implemented 
 class X509Error(LibCryptoError):
        """
        Exception, generated when some openssl function fail
@@ -16,6 +85,10 @@ class X509Name:
        """
        Class which represents X.509 distinguished name - typically 
        a certificate subject name or an issuer name.
+
+       Now used only to represent information, extracted from the
+       certificate. Potentially can be also used to build DN when creating
+       certificate signing request
        """
        # XN_FLAG_SEP_COMMA_PLUS & ASN1_STRFLG_UTF8_CONVERT
        PRINT_FLAG=0x10010
@@ -170,10 +243,10 @@ class X509:
                @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 stora and key are mutually exclusive. If neither is specified, attempts to verify
+               @param key - PKey object with open key to validate signature
                
-               itself as self-signed certificate
+               parameters store and key are mutually exclusive. If neither 
+               is specified, attempts to verify self as self-signed certificate
                """
                if store is not None and key is not None:
                        raise X509Error("key and store cannot be specified simultaneously")
@@ -216,16 +289,30 @@ class X509:
                b=Membio()
                libcrypto.i2a_ASN1_INTEGER(b.bio,asnint)
                return int(str(b),16)
+       @property 
+       def version(self):
+               """ certificate version as integer. Really certificate stores 0 for
+               version 1 and 2 for version 3, but we return 1 and 3 """
+               asn1int=cast(self.cert,_px509)[0].cert_info[0].version
+               return libcrypto.ASN1_INTEGER_get(asn1int)+1
        @property
        def startDate(self):
                """ Certificate validity period start date """
                # Need deep poke into certificate structure (x)->cert_info->validity->notBefore 
-               raise NotImplementedError
+               global utc
+               asn1date=cast(self.cert,_px509)[0].cert_info[0].validity[0].notBefore
+               b=Membio()
+               libcrypto.ASN1_TIME_print(b.bio,asn1date)
+               return datetime.strptime(str(b),"%b %d %H:%M:%S %Y %Z").replace(tzinfo=utc)
        @property
        def endDate(self):
                """ Certificate validity period end date """
                # Need deep poke into certificate structure (x)->cert_info->validity->notAfter
-               raise NotImplementedError
+               global utc
+               asn1date=cast(self.cert,_px509)[0].cert_info[0].validity[0].notAfter
+               b=Membio()
+               libcrypto.ASN1_TIME_print(b.bio,asn1date)
+               return datetime.strptime(str(b),"%b %d %H:%M:%S %Y %Z").replace(tzinfo=utc)
        def extensions(self):
                """ Returns list of extensions """
                raise NotImplementedError
@@ -234,11 +321,14 @@ class X509:
                return libcrypto.X509_check_ca(self.cert)>0
 class X509Store:
        """
-               Represents trusted certificate store. Can be used to lookup CA certificates to verify
+               Represents trusted certificate store. Can be used to lookup CA 
+               certificates to verify
 
-               @param file - file with several certificates and crls to load into store
+               @param file - file with several certificates and crls 
+                               to load into store
                @param dir - hashed directory with certificates and crls
-               @param default - if true, default verify location (directory) is installed
+               @param default - if true, default verify location (directory) 
+                       is installed
 
        """
        def __init__(self,file=None,dir=None,default=False):
@@ -372,6 +462,9 @@ class StackOfX509:
                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.ASN1_TIME_print.argtypes=(c_void_p,c_void_p)
+libcrypto.ASN1_INTEGER_get.argtypes=(c_void_p,)
+libcrypto.ASN1_INTEGER_get.restype=c_long
 libcrypto.X509_get_serialNumber.argtypes=(c_void_p,)
 libcrypto.X509_get_serialNumber.restype=c_void_p
 libcrypto.X509_NAME_ENTRY_get_object.restype=c_void_p
@@ -386,3 +479,4 @@ 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 ec6b7821f2cfc210d821b8bc27ec5a4e8d89ee39..48494288f3bfaf7e06d1e7fb03d55399718eb32c 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,7 @@ class MyTests(distutils.cmd.Command):
 
 setup(
        name="ctypescrypto",
-       version="0.2.0",
+       version="0.2.4",
        description="CTypes-based interface for some OpenSSL libcrypto features",
        author="Victor Wagner",
        author_email="vitus@wagner.pp.ru",
index 2a09e78b562b869a8deea528333d34ab4126fbf5..011d487e770c78e9dee3d0d74f64cf3880e38ced 100644 (file)
@@ -1,9 +1,10 @@
 #!/usr/bin/env python
 # -*- encoding: utf-8 -*-
 
-from ctypescrypto.x509 import X509,X509Store
+from ctypescrypto.x509 import X509,X509Store,utc
 from ctypescrypto.oid import Oid
 from tempfile import NamedTemporaryFile
+import datetime
 import unittest
 
 
@@ -124,6 +125,12 @@ zVMSW4SOwg/H7ZMZ2cn6j1g0djIvruFQFGHUqFijyDATI+/GJYw2jxyA
                c=X509(self.cert1)
                self.assertEqual(c.subject[Oid("C")],"RU")
                self.assertEqual(c.subject[Oid("L")],u'\u041c\u043e\u0441\u043a\u0432\u0430')
+       def test_notBefore(self):
+               c=X509(self.cert1)
+               self.assertEqual(c.startDate,datetime.datetime(2014,10,26,19,07,17,0,utc))
+       def test_notAfter(self):
+               c=X509(self.cert1)
+               self.assertEqual(c.endDate,datetime.datetime(2024,10,23,19,7,17,0,utc))
        def test_namecomp(self):
                c=X509(self.cert1)
                ca=X509(self.ca_cert)
@@ -133,6 +140,9 @@ zVMSW4SOwg/H7ZMZ2cn6j1g0djIvruFQFGHUqFijyDATI+/GJYw2jxyA
        def test_serial(self):
                c=X509(self.cert1)
                self.assertEqual(c.serial,0xDF448E69DADC927CL)
+       def test_version(self):
+               c=X509(self.cert1)
+               self.assertEqual(c.version,3)
        def test_ca_cert(self):
                ca=X509(self.ca_cert)
                self.assertTrue(ca.check_ca())