1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 rhn.SSL builds an abstraction on top of the objects provided by pyOpenSSL
24 """
25
26 from OpenSSL import SSL
27
28 from OpenSSL import crypto
29 import os
30
31 import socket
32 import select
33 from rhn.i18n import bstr
34 import sys
35
36 DEFAULT_TIMEOUT = 120
37
38 if hasattr(socket, 'sslerror'):
39 socket_error = socket.sslerror
40 else:
41 from ssl import socket_error
42
44 """
45 Class that wraps a pyOpenSSL Connection object, adding more methods
46 """
47 - def __init__(self, socket, trusted_certs=None):
48
49 self._ctx = None
50
51 self._connection = None
52 self._sock = socket
53 self._trusted_certs = []
54
55 trusted_certs = trusted_certs or []
56 for f in trusted_certs:
57 self.add_trusted_cert(f)
58
59 self._ssl_method = SSL.SSLv23_METHOD
60
61 self._ssl_verify_flags = SSL.VERIFY_PEER
62
63
64 self._buffer_size = 8192
65
66
67 self._pos = 0
68
69 self._buffer = bstr("")
70
71
72 self._makefile_called = 0
73
74 self._closed = None
75
77 """
78 Adds a trusted certificate to the certificate store of the SSL context
79 object.
80 """
81 if not os.access(file, os.R_OK):
82 raise ValueError("Unable to read certificate file %s" % file)
83 self._trusted_certs.append(file.encode("utf-8"))
84
86 """
87 Initializes the SSL connection.
88 """
89 self._check_closed()
90
91 self._ctx = SSL.Context(self._ssl_method)
92 self._ctx.set_options(SSL.OP_NO_SSLv2)
93 self._ctx.set_options(SSL.OP_NO_SSLv3)
94 if self._trusted_certs:
95
96 for f in self._trusted_certs:
97 self._ctx.load_verify_locations(f)
98 else:
99
100 self._ssl_verify_flags = 0
101
102 self._ctx.set_verify(self._ssl_verify_flags, ssl_verify_callback)
103 if hasattr(SSL, "OP_DONT_INSERT_EMPTY_FRAGMENTS"):
104
105
106
107
108 self._ctx.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
109
110
111 self._connection = SSL.Connection(self._ctx, self._sock)
112
113
114 if server_name is not None:
115 self._connection.set_tlsext_host_name(server_name.encode("utf8"))
116
117 self._connection.set_connect_state()
118
119 - def makefile(self, mode, bufsize=None):
120 """
121 Returns self, since we are a file-like object already
122 """
123 if bufsize:
124 self._buffer_size = bufsize
125
126
127
128
129 self._makefile_called = self._makefile_called + 1
130 return self
131
133 """
134 Closes the SSL connection
135 """
136
137
138
139 if self._closed:
140
141 return
142 if not self._makefile_called:
143 self._really_close()
144 return
145 self._makefile_called = self._makefile_called - 1
146
147
148
151
153
154 if self._connection is None:
155 return
156 get_state = None
157 try:
158 get_state = getattr(self._connection, 'state_string')
159 except AttributeError:
160 get_state = getattr(self._connection, 'get_state_string')
161
162 if get_state is not None:
163
164 if sys.version_info[0] == 3:
165 if get_state() == b'SSL negotiation finished successfully':
166 self._connection.shutdown()
167
168 else:
169 if get_state() == 'SSL negotiation finished successfully':
170 self._connection.shutdown()
171
172 self._connection.close()
173 self._closed = 1
174
176 if self._closed:
177 raise ValueError("I/O operation on closed file")
178
180 if hasattr(self._connection, name):
181 return getattr(self._connection, name)
182 raise AttributeError(name)
183
184
186 """
187 Returns false always.
188 """
189 return 0
190
193
194 - def seek(self, pos, mode=0):
195 raise NotImplementedError("seek")
196
197 - def read(self, amt=None):
198 """
199 Reads up to amt bytes from the SSL connection.
200 """
201 self._check_closed()
202
203
204
205
206 buffer_size = self._buffer_size
207
208 buffer_length = len(self._buffer)
209
210 while buffer_length < amt or amt is None:
211
212 if amt is not None:
213 buffer_size = min(amt - buffer_length, buffer_size)
214
215 try:
216 data = self._connection.recv(buffer_size)
217
218 self._buffer = self._buffer + data
219 buffer_length = len(self._buffer)
220
221
222 pending = self._connection.pending()
223 if pending == 0:
224
225 break
226 except SSL.ZeroReturnError:
227
228 break
229 except SSL.SysCallError:
230 e = sys.exc_info()[1]
231 print("SSL exception", e.args)
232 break
233 except SSL.WantWriteError:
234 self._poll(select.POLLOUT, 'read')
235 except SSL.WantReadError:
236 self._poll(select.POLLIN, 'read')
237
238 if amt:
239 ret = self._buffer[:amt]
240 self._buffer = self._buffer[amt:]
241 else:
242 ret = self._buffer
243 self._buffer = bstr("")
244
245 self._pos = self._pos + len(ret)
246 return ret
247
249 buf[:] = self.read(len(buf))
250 return len(buf)
251
252 - def _poll(self, filter_type, caller_name):
258
260 """
261 Writes to the SSL connection.
262 """
263 self._check_closed()
264
265
266
267 origlen = len(data)
268 while True:
269 try:
270 sent = self._connection.send(data)
271 if sent == len(data):
272 break
273 data = data[sent:]
274 except SSL.WantWriteError:
275 self._poll(select.POLLOUT, 'write')
276 except SSL.WantReadError:
277 self._poll(select.POLLIN, 'write')
278
279 return origlen
280
281 - def recv(self, amt):
282 return self.read(amt)
283
284 send = write
285
286 sendall = write
287
289 """
290 Reads a single line (up to `length' characters long) from the SSL
291 connection.
292 """
293 self._check_closed()
294 while True:
295
296
297 charcount = None
298 i = self._buffer.find(bstr('\n'))
299 if i >= 0:
300
301 charcount = i + 1
302 elif length and len(self._buffer) >= length:
303 charcount = length
304
305 if charcount is not None:
306 ret = self._buffer[:charcount]
307 self._buffer = self._buffer[charcount:]
308 self._pos = self._pos + len(ret)
309 return ret
310
311
312 bufsize = self._buffer_size
313 if length:
314
315 bufsize = min(self._buffer_size, length - len(self._buffer))
316
317 try:
318 data = self._connection.recv(bufsize)
319 self._buffer = self._buffer + data
320 except SSL.ZeroReturnError:
321
322 break
323 except SSL.WantWriteError:
324 self._poll(select.POLLOUT, 'readline')
325 except SSL.WantReadError:
326 self._poll(select.POLLIN, 'readline')
327
328
329 ret = self._buffer
330 self._buffer = ""
331 self._pos = self._pos + len(ret)
332 return ret
333
334
336 """
337 Verify callback, which will be called for each certificate in the
338 certificate chain.
339 """
340
341 return ok
342
344
347
349 return "Timeout Exception"
350