1 /* This is the specifics module for SWIG mapping to Python.
2 * It includes generic definitions from ../swig-tlspool.i
4 * This separation enables us to override function names, for instance
5 * to raw/internal names, and then to add language-specific wrappers.
7 * From: Rick van Rein <rick@openfortress.nl>
13 /* Renames, prefixing "_" when wrapped below for better parameter handling
15 %rename(_pid) tlspool_pid;
16 %rename(_open_poolhandle) tlspool_open_poolhandle;
17 %rename(_ping) tlspool_ping;
18 %rename(_starttls) tlspool_starttls;
19 %rename(_control_detach) tlspool_control_detach;
20 %rename(_control_reattach) tlspool_control_reattach;
21 %rename(_prng) tlspool_prng;
24 // type maps to translate between SWIG's abstract data types and Python types
26 %typemap(in) ctlkey_t {
28 if ((PyString_AsStringAndSize ($input, (char **) &($1), &inlen) == -1) || (inlen != TLSPOOL_CTLKEYLEN)) {
29 PyErr_SetString (PyExc_ValueError, "Control keys are binary strings of length 16");
34 %typemap(out) ctlkey_t {
35 if ($result == NULL) {
38 $1 = PyString_FromStringAndSize ($result, TLSPOOL_CTLKEYLEN);
43 // apply the settings above as modifiers to the generic TLS Pool wrapping
45 %include "../swig-tlspool.i"
48 // helper function to raise OSError with the parameter set to C-reachable errno
52 PyObject *raise_errno (void) {
53 return PyErr_SetFromErrno (PyExc_OSError);
60 // full-blown Python code to include
68 if not 'IPPROTO_SCTP' in dir (socket):
69 socket.IPPROTO_SCTP = 132
72 def pid (pidfile=None):
73 """This function returns the process identity of the TLS Pool.
74 When no pidfile is provided, the default path as configured in the
75 TLS Pool libary will be used. An Exception is thrown when there is
78 process_id = _pid (pidfile)
80 _tlspool.raise_errno ()
84 def open_poolhandle (path=None):
85 """This function returns the OS-specific socket handle value for the
86 TLS Pool. It is already connected, and shared with the internal
87 management of this module, so it must not be closed by the caller.
88 When no path is provided, the default path is used instead.
89 This function blocks until a connection to the TLS Pool succeeds.
90 The path is only used in the first call, and only when no prior
91 contact to the TLS Pool has been made; if that has happened, then
92 this function returns the previously found socket handle.
94 fd = _open_poolhandle (path)
96 _tlspool.raise_errno ()
100 def ping (YYYYMMDD_producer=_tlspool.TLSPOOL_IDENTITY_V2,
101 facilities=_tlspool.PIOF_FACILITY_ALL_CURRENT):
102 """This function takes in a string with a date in YYYYMMDD format, followed
103 by a user@domain producer identifier. It takes in an integer value
104 that is the logical or of PIOF_FACILITY_xxx values. This is sent to
105 the TLS Pool through tlspool_ping() and the response is returned as a
106 similar tuple (YYYYMMDD_producer, facilities) as returned by the
107 TLS Pool. This function blocks until a connection to the TLS Pool has
108 been found. It is a good first command to send to the TLS Pool.
111 pp.YYYYMMDD_producer = YYYYMMDD_producer
112 pp.facilities = facilities
114 _tlspool.raise_errno ()
116 return (pp.YYYYMMDD_producer, pp.facilities)
118 def make_tlsdata (localid='', remoteid='',
119 flags=0, local_flags=0,
120 ipproto=socket.IPPROTO_TCP, streamid=0, service='',
121 timeout=0, ctlkey=None):
122 """Make a new tlsdata structure, based the fields that may be supplied
123 as flags, or otherwise as defaults. Note that the field "local" is
124 renamed to "local_flags" for reasons of clarity. This helper function
125 returns a tlsdata structure or raises an exception.
127 tlsdata = starttls_data ()
128 if ctlkey is not None:
129 tlsdata.ctlkey = ctlkey
130 tlsdata.service = service
131 tlsdata.localid = localid
132 tlsdata.remoteid = remoteid
133 tlsdata.flags = flags
134 tlsdata.local = local_flags
135 tlsdata.ipproto = ipproto
136 tlsdata.streamid = streamid
137 tlsdata.timeout = timeout
141 """The tlspool.Connection class wraps around a connection to be protected
142 by the TLS Pool. It uses the global socket for attaching to the
143 TLS Pool, but the individual instances of this class do represent
144 individual connections managed by the TLS Pool.
145 New instances can already collect a large number of parameters
146 that end up in the tlsdata structure of tlspool_starttls(),
147 but these values may also be created through getters/setters.
148 Some values have reasonable defaults, but some must have been
149 set before invoking the starttls() method on the instance.
150 The tlsdata fields all have defaults, as specified under
151 tlspool.make_tlsdata().
154 def __init__ (self, cryptsocket, plainsocket=None, **tlsdata):
155 self.cryptsk = cryptsocket
156 self.cryptfd = cryptsocket.fileno ()
157 self.plainsk = plainsocket
158 self.plainfd = plainsocket.fileno () if plainsocket else -1
159 self.tlsdata = make_tlsdata (**tlsdata)
162 assert (self.plainsk is not None)
163 assert (self.plainfd >= 0)
164 self.plainsk.close ()
168 def tlsdata_get (self, tlsvar):
169 return self.tlsdata [tlsvar]
171 def tlsdata_set (self, tlsvar, value):
172 self.tlsdata [tlsvar] = value
175 """Initiate a TLS connection with the current settings, as
176 provided during instantiation or through getter/setter
177 access afterwards. The variables that are required at
178 this point are service and, already obliged when making
179 a new instance, cryptfd.
181 assert (self.cryptsk is not None)
182 assert (self.cryptfd >= 0)
183 assert (self.tlsdata.service != '')
185 af = self.cryptsk.family
189 if self.cryptsk.proto in [socket.IPPROTO_UDP]:
190 socktp = socket.SOCK_DGRAM
191 elif self.cryptsk.proto in [socket.IPPROTO_SCTP]:
192 socktp = socket.SOCK_SEQPACKET
194 socktp = socket.SOCK_STREAM
196 socktp = socket.SOCK_STREAM
197 plainsockptr = socket_data ()
198 plainsockptr.unix_socket = self.plainfd
199 # Provide None for the callback function, SWIG won't support it
200 # We might at some point desire a library of C routine options?
201 rv = _starttls (self.cryptfd, self.tlsdata, plainsockptr, None)
206 _tlspool.raise_errno ()
207 if self.plainsk is None:
208 self.plainfd = plainsockptr.unix_socket
209 self.plainsk = socket.fromfd (self.plainfd, af, socktp)
212 def prng (self, length, label, ctxvalue=None):
213 """Produce length bytes of randomness from the master key, after
214 mixing it with the label and optional context value in ctxvalue.
215 The procedure has been described in RFC 5705.
216 #TODO# Find a way to return the random bytes, and use the length
219 rv = _prng (label, ctxvalue, length, buf, self.tlsdata.ctlkey)
221 _tlspool.raise_errno ()
225 def control_detach (self):
226 """Detach control of this connection. Although the connection
227 itself will still be available, control over it is diminished
228 and its continuation is no longer dependent on the current
229 connection. You may need to pass tlsdata.ctlkey to another
230 process, or use control_reattach(), before this is reversed
231 in this process or another.
233 _control_detach (self.tlsdata.ctlkey)
235 def control_reattach (self, ctlkey=None):
236 """Reattach control of this connection. The connection may have
237 called control_detach() in this process or another. To help
238 with the latter case, its tlsdata.ctlkey must have been moved
241 _control_reattach (self.tlsdata.ctlkey)
244 """The SecurityMixIn class can be added as a subclass before a
245 (subclass of) SocketServer.BaseServer and it adds the facilities
246 of starttls(), startgss() and startssh() which add security through
247 one of the mechanisms. In addition, have_xxx() can be used to
248 query in advance if startxxx() should be doable with the present
249 combination of TLS Pool and client code.
251 Set a tlsdata field in the subclass, using the tlspool.make_tlsdata()
252 helper function, to bootstrap the same kind of behaviour on all
253 clients for which this class will be instantiated. Such a tlsdata
254 class variable will automatically be cloned into instances.
257 from tlspool import SecurityMixIn
258 from SocketServer import BaseHandler
260 class MyHandler (SecurityMixIn, BaseHandler):
262 tlsdata = make_tlsdata (service=...)
268 def handle_secure (self):
271 Alternatively, you can setup the tlsdata structure, or any part of it,
272 at a later time, through the tlsdata variable that will then be
273 instantiated during object initialisation. Any such changes to fields
274 must be completed before invoking starttls() on this object.
281 if self.tlsdata is None:
282 self.tlsdata = make_tlsdata ()
285 """Check whether STARTTLS is supported on the current TLS Pool"""
286 if self._pingdata is None:
287 self._pingdata = ping ()
288 return (self._pingdata [1] & PIOF_FACILITY_STARTTLS) != 0
291 """Check whether STARTSSH is supported on the current TLS Pool"""
292 if self._pingdata is None:
293 self._pingdata = ping ()
294 return (self._pingdata [1] & PIOF_FACILITY_STARTSSH) != 0
297 """Check whether STARTGSS is supported on the current TLS Pool"""
298 if self._pingdata is None:
299 self._pingdata = ping ()
300 return (self._pingdata [1] & PIOF_FACILITY_STARTGSS) != 0
303 """Modify the current socket to make it a TLS socket. Use the
304 tlsdata as currently setup (see class-level documentation).
305 Afterwards, call handle_secure() to start from scratch with
306 a secure connection. Also see the man page on the underlying
307 C library call, tlspool_starttls(3).
309 Some protocols start TLS immediately, for instance HTTPS;
310 for such protocols, the handle() method would immediately
311 call starttls() and the actual handler code would move
312 into secure_handle().
314 Other protocols, such as XMPP and IMAP, start in plaintext
315 and exchange pleasantries until they agree on running TLS.
316 This is the point where starttls() can be invoked.
318 The methods startssh() and startgss() are place holders for
319 future alternatives to start other security wrappers than
320 TLS, after negotiating them in a manner similar to STARTTLS.
322 if type (self.request) == tuple:
323 sox = self.request [1]
326 assert (type (sox) == socket._socketobject)
332 if sox.proto in [socket.IPPROTO_UDP]:
333 socktp = socket.SOCK_DGRAM
334 elif sox.proto in [socket.IPPROTO_SCTP]:
335 socktp = socket.SOCK_SEQPACKET
337 socktp = socket.SOCK_STREAM
339 socktp = socket.SOCK_STREAM
340 plainsockptr = socket_data ()
341 plainsockptr.unix_socket = -1
342 rv = _starttls (sox.fileno (), self.tlsdata, plainsockptr, None)
344 _tlspool.raise_errno ()
345 assert (plainsockptr.unix_socket >= 0)
346 sox2 = socket.fromfd (plainsockptr.unix_socket, af, socktp)
347 if type (self.request) == tuple:
348 self.request [1] = sox2
351 self.handle_secure ()
354 raise NotImplementedError ("Python wrapper does not implement STARTSSH")
357 raise NotImplementedError ("Python wrapper does not implement STARTGSS")
360 """When not overridden, the handle() method replaces the one in
361 later-mentioned classes in the inheritance structure. This
362 means that this is the default behaviour when the SecureMixIn
363 precedes the handler class. This particular version of handle()
364 does nothing but invoke starttls(), which in turn invokes
365 handle_secure() after the TLS handshake has succeeded.
367 print 'STARTTLS.BEGIN'
371 def handle_secure (self):
372 """This method may be overridden to handle the secure part of the
373 connection, after starttls() has been called from within
374 handle(). This function is special in the sense that it may
375 refer to self.tlsdata and rely on the localid and remoteid
376 as being negotiated over TLS.
378 Since any prior actions in handle() are usually unauthenticated,
379 it is common to start from scratch with the protocol. The secure
380 layer however, tends to enable more features, such as blunt
381 password submission and, perhaps, privileged operations available
382 to the authenticated self.tlsdata.remoteid user.
384 As an example, if the handler class is BaseHTTPRequestHandler,
385 its handle() method could be invoked on the secured content
386 (possibly after authorisation) with an override as follows:
388 def handle_secure (self):
389 BaseHTTPRequestHandler.handle (self)