]> www.wagner.pp.ru Git - oss/ctypescrypto.git/commitdiff
Implemented access to certificate fields by poking structure. Functions version,...
authorVictor Wagner <wagner@atlas-card.ru>
Fri, 19 Dec 2014 10:26:54 +0000 (13:26 +0300)
committerVictor Wagner <wagner@atlas-card.ru>
Fri, 19 Dec 2014 10:26:54 +0000 (13:26 +0300)
ctypescrypto/x509.py
setup.py
tests/testx509.py

index e2c97c669d114ddcbcb1e2f2707ecedc7e7c3751..bd056d32f6227bcba4593e26fd79d06504ee5097 100644 (file)
@@ -8,14 +8,70 @@ such as CMS, OCSP and timestamps.
 
 
 
 
 
 
-from ctypes import c_void_p,create_string_buffer,c_long,c_int,POINTER,c_char_p
+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 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']
 
 __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):
        """
 # X509_extlist is not exported yet, because is not implemented 
 class X509Error(LibCryptoError):
        """
@@ -233,16 +289,30 @@ class X509:
                b=Membio()
                libcrypto.i2a_ASN1_INTEGER(b.bio,asnint)
                return int(str(b),16)
                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 
        @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
        @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
        def extensions(self):
                """ Returns list of extensions """
                raise NotImplementedError
@@ -392,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.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
 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
@@ -406,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))
 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",
 
 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",
        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 -*-
 
 #!/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
 from ctypescrypto.oid import Oid
 from tempfile import NamedTemporaryFile
+import datetime
 import unittest
 
 
 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')
                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)
        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_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())
        def test_ca_cert(self):
                ca=X509(self.ca_cert)
                self.assertTrue(ca.check_ca())