]> 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 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):
        """
@@ -233,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
@@ -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.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
@@ -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))
+
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())