]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - ctypescrypto/bio.py
Python 3 support for modules pbkdf2 pkey ec x509
[oss/ctypescrypto.git] / ctypescrypto / bio.py
1 """
2 Interface to OpenSSL BIO library
3 """
4 from ctypescrypto import libcrypto,pyver, inttype, chartype
5 from ctypes import c_char_p, c_void_p, c_int, string_at, c_long
6 from ctypes import POINTER, byref, create_string_buffer
7 class Membio(object):
8     """
9     Provides interface to OpenSSL memory bios
10     use str() or unicode() to get contents of writable bio
11     use bio member to pass to libcrypto function
12     
13     """
14     def __init__(self, data=None, clone=False):
15         """
16         If data is specified, creates read-only BIO. 
17         If clone is True, makes copy of data in the instance member
18         If data is
19         None, creates writable BIO, contents of which can be retrieved
20         by str() or unicode()
21         
22         """
23         if data is None:
24             method = libcrypto.BIO_s_mem()
25             self.bio = libcrypto.BIO_new(method)
26         else:
27             if isinstance(data, chartype):
28                 data = data.encode("utf-8")
29                 clone = True
30             if clone :
31                 self.data = data
32                 self.bio = libcrypto.BIO_new_mem_buf(c_char_p(self.data), len(data))
33             else:
34                 self.bio = libcrypto.BIO_new_mem_buf(c_char_p(data), len(data))
35                 
36     def __del__(self):
37         """
38         Cleans up memory used by bio
39         """
40         if hasattr(self,'bio'):
41             libcrypto.BIO_free(self.bio)
42             del self.bio
43
44     def __bytes__(self):
45         """
46         Returns current contents of buffer as byte string
47         """
48         string_ptr = c_char_p(None)
49         string_len = libcrypto.BIO_ctrl(self.bio, 3, 0, byref(string_ptr))
50         return string_at(string_ptr, string_len)
51
52     def __unicode__(self):
53         """
54         Attempts to interpret current contents of buffer as UTF-8 string
55         and convert it to unicode
56         """
57         return self.__bytes__().decode("utf-8")
58     if pyver == 2:
59         __str__ = __bytes__
60     else: 
61         __str__ = __unicode__
62     def read(self, length=None):
63         """
64         Reads data from readble BIO. For test purposes.
65         @param length - if specifed, limits amount of data read.
66         If not BIO is read until end of buffer
67         """
68         if not length is None:
69             if not isinstance(length, inttype) :
70                 raise TypeError("length to read should be number")
71             buf = create_string_buffer(length)
72             readbytes = libcrypto.BIO_read(self.bio, buf, length)
73             if readbytes == -2:
74                 raise NotImplementedError("Function is not supported by" +
75                                           "this BIO")
76             if readbytes == -1:
77                 raise IOError
78             if readbytes == 0:
79                 return b""
80             return buf.raw[:readbytes]
81         else:
82             buf = create_string_buffer(1024)
83             out = b""
84             readbytes = 1
85             while readbytes > 0:
86                 readbytes = libcrypto.BIO_read(self.bio, buf, 1024)
87                 if readbytes == -2:
88                     raise NotImplementedError("Function is not supported by " +
89                                               "this BIO")
90                 if readbytes == -1:
91                     raise IOError
92                 if readbytes > 0:
93                     out += buf.raw[:readbytes]
94             return out
95
96     def write(self, data):
97         """
98         Writes data to writable bio. For test purposes
99         """
100         if pyver == 2:
101              if isinstance(data, unicode):
102                 data = data.encode("utf-8")
103              else:
104                 data = str(data)
105         else:
106              if not isinstance(data, bytes): 
107                 data=str(data).encode("utf-8")   
108
109         written = libcrypto.BIO_write(self.bio, data, len(data))
110         if written == -2:
111             raise NotImplementedError("Function not supported by this BIO")
112         if written < len(data):
113             raise IOError("Not all data were successfully written")
114
115     def reset(self):
116         """
117         Resets the read-only bio to start and discards all data from
118         writable bio
119         """
120         libcrypto.BIO_ctrl(self.bio, 1, 0, None)
121
122 __all__ = ['Membio']
123 libcrypto.BIO_s_mem.restype = c_void_p
124 libcrypto.BIO_new.restype = c_void_p
125 libcrypto.BIO_new.argtypes = (c_void_p, )
126 libcrypto.BIO_ctrl.restype = c_long
127 libcrypto.BIO_ctrl.argtypes = (c_void_p, c_int, c_long, POINTER(c_char_p))
128 libcrypto.BIO_read.argtypes = (c_void_p, c_char_p, c_int)
129 libcrypto.BIO_write.argtypes = (c_void_p, c_char_p, c_int)
130 libcrypto.BIO_free.argtypes = (c_void_p, )
131 libcrypto.BIO_new_mem_buf.restype = c_void_p
132 libcrypto.BIO_new_mem_buf.argtypes = (c_char_p, c_int)