]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - ctypescrypto/oid.py
Begin to implement python3 support. Now tests for oid, bio, cipher, digest, mac and...
[oss/ctypescrypto.git] / ctypescrypto / oid.py
1 """
2 Interface to OpenSSL object identifier database.
3
4 It is primarily intended to deal with OIDs which are compiled into the
5 database or defined in the openssl configuration files.
6
7 But see create() function.
8
9 OpenSSL maintains database of OIDs, which contain long and short
10 human-readable names, which correspond to Oid as well as canonical
11 dotted-decimal representation, and links it to small integer, named
12 numeric identifier or 'nid'. Most OpenSSL functions which deals with
13 ASN.1 structures such as certificates or cryptographic messages,
14 expect or return nids, but it is very bad idea to hardcode nids into
15 your app, because it can change after mere recompilation of OpenSSL
16 library.
17
18 This module provides Oid object which represents entry to OpenSSL
19 OID database.
20 """
21 from ctypescrypto import libcrypto, pyver,bintype,chartype,inttype
22 from ctypes import c_char_p, c_void_p, c_int, create_string_buffer
23 from ctypescrypto.exception import LibCryptoError
24
25 __all__ = ['Oid', 'create', 'cleanup']
26
27 class Oid(object):
28     """
29     Represents an OID (ASN.1 Object identifier).
30
31
32     It can be consturucted by textual
33     representation like Oid("commonName") or Oid("CN"),
34     dotted-decimal Oid("1.2.3.4") or using OpenSSL numeric
35     identifer (NID), which is typically returned or required by
36     OpenSSL API functions. If object is consturcted from textual
37     representation which is not present in the database, it fails
38     with ValueError
39
40     attribute nid - contains object nid.
41     """
42
43     def __init__(self, value):
44         """
45         Object constructor. Accepts string, integer, or another Oid
46         object.
47
48         Integer should be OpenSSL numeric identifier (nid) as returned
49         by some libcrypto function or extracted from some libcrypto
50         structure
51         """
52         if isinstance(value, chartype):
53             value = value.encode('ascii')
54         if isinstance(value, bintype):
55             self.nid = libcrypto.OBJ_txt2nid(value)
56             if self.nid == 0:
57                 raise ValueError("Cannot find object %s in the database" %
58                                  value)
59         elif isinstance(value, inttype):
60             short = libcrypto.OBJ_nid2sn(value)
61             if short is None:
62                 raise ValueError("No such nid %d in the database" % value)
63             self.nid = value
64         elif isinstance(value, Oid):
65             self.nid = value.nid
66         else:
67             raise TypeError("Cannot convert this type to object identifier")
68     def __hash__(self):
69         " Hash of object is equal to nid because Oids with same nid are same"
70         return self.nid
71     def __eq__ (self, other):
72         return self.nid == other.nid
73     def __hash__(self):
74         """ Returns NID of object as hash value. Should make Oids with 
75           identical NID compare equal and also let use Oids as
76           dictionary keys"""
77         return self.nid
78     def __str__(self):
79         " Default string representation of Oid is dotted-decimal "
80         return self.dotted()
81     def __repr__(self):
82         " Returns constructor call of Oid with dotted representation "
83         return "Oid('%s')" % (self.dotted())
84     if pyver == 2:
85         def shortname(self):
86             " Returns short name if any "
87             return libcrypto.OBJ_nid2sn(self.nid)
88         def longname(self):
89             " Returns long name if any "
90             return  libcrypto.OBJ_nid2ln(self.nid)
91     else:
92         def shortname(self):
93             " Returns short name if any "
94             return libcrypto.OBJ_nid2sn(self.nid).decode('utf-8')
95         def longname(self):
96             " Returns long name if any "
97             return  libcrypto.OBJ_nid2ln(self.nid).decode('utf-8')
98             
99     def dotted(self):
100         " Returns dotted-decimal reperesentation "
101         obj = libcrypto.OBJ_nid2obj(self.nid)
102         buf = create_string_buffer(256)
103         libcrypto.OBJ_obj2txt(buf, 256, obj, 1)
104         if pyver == 2:
105             return buf.value
106         else:
107             return buf.value.decode('ascii')
108     @staticmethod
109     def fromobj(obj):
110         """
111         Creates an OID object from the pointer to ASN1_OBJECT c structure.
112         This method intended for internal use for submodules which deal
113         with libcrypto ASN1 parsing functions, such as x509 or CMS
114         """
115         nid = libcrypto.OBJ_obj2nid(obj)
116         if nid == 0:
117             buf = create_string_buffer(80)
118             dotted_len = libcrypto.OBJ_obj2txt(buf, 80, obj, 1)
119             dotted = buf[:dotted_len]
120             oid = create(dotted, dotted, dotted)
121         else:
122             oid = Oid(nid)
123         return oid
124
125 def create(dotted, shortname, longname):
126     """
127     Creates new OID in the database
128
129     @param dotted - dotted-decimal representation of new OID
130     @param shortname - short name for new OID
131     @param longname - long name for new OID
132
133     @returns Oid object corresponding to new OID
134
135     This function should be used with exreme care. Whenever
136     possible, it is better to add new OIDs via OpenSSL configuration
137     file
138
139     Results of calling this function twice for same OIDor for
140     Oid alredy in database are undefined
141
142     """
143     if pyver  > 2:
144         dotted = dotted.encode('ascii')
145         shortname = shortname.encode('utf-8')
146         longname = longname.encode('utf-8')
147     nid = libcrypto.OBJ_create(dotted, shortname, longname)
148     if nid == 0:
149         raise LibCryptoError("Problem adding new OID to the  database")
150     return Oid(nid)
151
152 def cleanup():
153     """
154     Removes all the objects, dynamically added by current
155     application from database.
156
157     Note that in OpenSSL 1.1.0 and above OBJ_cleanup really does nothing
158     """
159     if hasattr(libcrypto,"OBJ_cleanup"):
160         libcrypto.OBJ_cleanup()
161
162 libcrypto.OBJ_nid2sn.restype = c_char_p
163 libcrypto.OBJ_nid2ln.restype = c_char_p
164 libcrypto.OBJ_nid2obj.restype = c_void_p
165 libcrypto.OBJ_obj2nid.restype = c_int
166 libcrypto.OBJ_obj2txt.argtypes = (c_char_p, c_int, c_void_p, c_int)
167 libcrypto.OBJ_txt2nid.argtupes = (c_char_p, )
168 libcrypto.OBJ_obj2nid.argtupes = (c_void_p, )
169 libcrypto.OBJ_create.argtypes = (c_char_p, c_char_p, c_char_p)