From 9a07daa396adaf452414e02fdaf3746351746224 Mon Sep 17 00:00:00 2001 From: Victor Wagner Date: Thu, 5 Jun 2014 11:59:23 +0400 Subject: [PATCH] Added first test file - for oid module --- MANIFEST.in | 1 + ctypescrypto/oid.py | 78 ++++++++++++++++++++++++++++++++++++++++++--- setup.py | 44 +++++++++++++++++++++++++ tests/testoids.py | 69 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 MANIFEST.in create mode 100644 setup.py create mode 100644 tests/testoids.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..16b52e4 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include tests/*.py diff --git a/ctypescrypto/oid.py b/ctypescrypto/oid.py index 81bea92..9852043 100644 --- a/ctypescrypto/oid.py +++ b/ctypescrypto/oid.py @@ -1,29 +1,97 @@ """ - Interface to OpenSSL object identifier database + Interface to OpenSSL object identifier database. + It is primarily intended to deal with OIDs which are compiled into the + database or defined in the openssl configuration files. + + But see create() function + """ from ctypescrypto import libcrypto +from ctypes import c_char_p, c_void_p, c_int, create_string_buffer class Oid: + """ + Represents an OID. It can be consturucted by textual + representation like Oid("commonName") or Oid("CN"), + dotted-decimal Oid("1.2.3.4") or using OpenSSL numeric + identifer (NID), which is typically returned or required by + OpenSSL API functions. If object is consturcted from textual + representation which is not present in the database, it fails + with ValueError + + attribute nid - contains object nid. + + + """ + def __init__(self,value): + " Object constuctor. Accepts string or integer" if type(value) == type(""): self.nid=libcrypto.OBJ_txt2nid(value) if self.nid==0: - raise LibCryptoError("Cannot find object %s in the - database"%(value)) + raise ValueError("Cannot find object %s in the database"%(value)) elif type(value) == type(0): + cn=libcrypto.OBJ_nid2sn(value) + if cn is None: + raise ValueError("No such nid %d in the database"%(value)) self.nid=value else: raise TypeError("Cannot convert this type to object identifier") + def __hash__(self): + " Returns NID " + return self.nid def __cmp__(self,other): + " Compares NIDs of two objects " return self.nid-other.nid def __str__(self): + " Default string representation of Oid is dotted-decimal" return self.dotted() - def shorttname(self): + def __repr__(self): + return "Oid('%s')"%(self.dotted()) + def shortname(self): + " Returns short name if any " return libcrypto.OBJ_nid2sn(self.nid) def longname(self): + " Returns logn name if any " return libcrypto.OBJ_nid2ln(self.nid) - def dotted(self) + def dotted(self): + " Returns dotted-decimal reperesntation " obj=libcrypto.OBJ_nid2obj(self.nid) buf=create_string_buffer(256) libcrypto.OBJ_obj2txt(buf,256,obj,1) return buf.value +def create(dotted,shortname,longname): + """ + Creates new OID in the database + + @param dotted - dotted-decimal representation of new OID + @param shortname - short name for new OID + @param longname - long name for new OID + + @returns Oid object corresponding to new OID + + This function should be used with exreme care. Whenever + possible, it is better to add new OIDs via OpenSSL configuration + file + + Results of calling this function twice for same OIDor for + Oid alredy in database are undefined + """ + nid=libcrypto.OBJ_create(dotted,shortname,longname) + if nid == 0: + raise LibCryptoError("Problem adding new OID to the database") + return Oid(nid) + +def cleanup(): + """ + Removes all the objects, dynamically added by current + application from database. + """ + libcrypto.OBJ_cleanup() + +libcrypto.OBJ_nid2sn.restype=c_char_p +libcrypto.OBJ_nid2ln.restype=c_char_p +libcrypto.OBJ_nid2obj.restype=c_void_p +libcrypto.OBJ_obj2txt.argtypes=(c_char_p,c_int,c_void_p,c_int) +libcrypto.OBJ_txt2nid.argtupes=(c_char_p,) +libcrypto.OBJ_create.argtypes=(c_char_p,c_char_p,c_char_p) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b6f1b2b --- /dev/null +++ b/setup.py @@ -0,0 +1,44 @@ +from distutils.core import setup +import distutils.cmd +import sys,os + +class MyTests(distutils.cmd.Command): + user_options=[] + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + sys.path.insert(0,os.getcwd()) + import unittest + result=unittest.TextTestResult(sys.stdout,True,True) + suite= unittest.defaultTestLoader.discover("./tests") + print "Discovered %d test cases"%suite.countTestCases() + result.buffer=True + suite.run(result) + print "" + if not result.wasSuccessful(): + if len(result.errors): + print "============ Errors disovered =================" + for r in result.errors: + print r[0],":",r[1] + + if len(result.failures): + print "============ Failures disovered =================" + for r in result.failures: + print r[0],":",r[1] + sys.exit(1) + else: + print "All tests successful" + +setup( + name="ctypescrypto" + version="0.2.0" + description="CTypes-based interface for some OpenSSL libcrypto features" + author="Victor Wagner", + author_email="vitus@wagner.pp.ru", + url="https://github.com/vbwagner/ctypescrypto", + packages=["ctypescrypto"], + cmdlass={"test":MyTests} +) + diff --git a/tests/testoids.py b/tests/testoids.py new file mode 100644 index 0000000..f324f7e --- /dev/null +++ b/tests/testoids.py @@ -0,0 +1,69 @@ +from ctypescrypto.oid import Oid,create,cleanup +import unittest + +class TestStandard(unittest.TestCase): + def test_cn(self): + o=Oid("2.5.4.3") + self.assertEqual(repr(o),"Oid('2.5.4.3')") + self.assertEqual(o.dotted(),"2.5.4.3") + self.assertEqual(str(o),"2.5.4.3") + self.assertEqual(o.shortname(),"CN") + self.assertEqual(o.longname(),"commonName") + def test_getnid(self): + o=Oid("2.5.4.3") + x=Oid("CN") + self.assertEqual(o.nid,x.nid) + self.assertEqual(o,x) + self.assertEqual(hash(o),hash(x)) + + def test_cons2(self): + o=Oid("2.5.4.3") + x=Oid("commonName") + self.assertEqual(o.nid,x.nid) + def test_bynid(self): + o=Oid("2.5.4.3") + x=Oid(o.nid) + self.assertEqual(o.nid,x.nid) + def test_wrongoid(self): + with self.assertRaises(ValueError): + o=Oid("1.2.3.4.5.6.7.8.10.111.1111") + def test_wrongname(self): + with self.assertRaises(ValueError): + o=Oid("No such oid in the database") + def test_wrongtype(self): + with self.assertRaises(TypeError): + o=Oid([2,5,3,4]) + +class TestCustom(unittest.TestCase): + def testCreate(self): + d='1.2.643.100.3' + sn="SNILS" + long_name="Russian Pension security number" + o=create(d,sn,long_name) + self.assertEqual(str(o),d) + self.assertEqual(o.shortname(),sn) + self.assertEqual(o.longname(),long_name) + def testLookup(self): + d='1.2.643.100.3' + sn="SNILS" + long_name="Russian Pension security number" + o=create(d,sn,long_name) + x=Oid(sn) + self.assertEqual(o,x) + def testCleanup(self): + d='1.2.643.100.3' + sn="SNILS" + long_name="Russian Pension security number" + o=create(d,sn,long_name) + cleanup() + with self.assertRaises(ValueError): + x=Oid(sn) + def tearDown(self): + # Always call cleanup before next test + cleanup() + + + + +if __name__ == '__main__': + unittest.main() -- 2.39.2