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 {
38 $result = PyString_FromStringAndSize ($1, 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
50 %nothread raise_errno;
54 PyObject *raise_errno (void) {
55 return PyErr_SetFromErrno (PyExc_OSError);
62 // full-blown Python code to include
70 if not 'IPPROTO_SCTP' in dir (socket):
71 socket.IPPROTO_SCTP = 132
74 def pid (pidfile=None):
75 """This function returns the process identity of the TLS Pool.
76 When no pidfile is provided, the default path as configured in the
77 TLS Pool libary will be used. An Exception is thrown when there is
80 process_id = _pid (pidfile)
82 _tlspool.raise_errno ()
86 def open_poolhandle (path=None):
87 """This function returns the OS-specific socket handle value for the
88 TLS Pool. It is already connected, and shared with the internal
89 management of this module, so it must not be closed by the caller.
90 When no path is provided, the default path is used instead.
91 This function blocks until a connection to the TLS Pool succeeds.
92 The path is only used in the first call, and only when no prior
93 contact to the TLS Pool has been made; if that has happened, then
94 this function returns the previously found socket handle.
96 fd = _open_poolhandle (path)
98 _tlspool.raise_errno ()
102 def ping (YYYYMMDD_producer=_tlspool.TLSPOOL_IDENTITY_V2,
103 facilities=_tlspool.PIOF_FACILITY_ALL_CURRENT):
104 """This function takes in a string with a date in YYYYMMDD format, followed
105 by a user@domain producer identifier. It takes in an integer value
106 that is the logical or of PIOF_FACILITY_xxx values. This is sent to
107 the TLS Pool through tlspool_ping() and the response is returned as a
108 similar tuple (YYYYMMDD_producer, facilities) as returned by the
109 TLS Pool. This function blocks until a connection to the TLS Pool has
110 been found. It is a good first command to send to the TLS Pool.
113 pp.YYYYMMDD_producer = YYYYMMDD_producer
114 pp.facilities = facilities
116 _tlspool.raise_errno ()
118 return (pp.YYYYMMDD_producer, pp.facilities)
120 def make_tlsdata (localid='', remoteid='',
121 flags=0, local_flags=0,
122 ipproto=socket.IPPROTO_TCP, streamid=0, service='',
123 timeout=0, ctlkey='TODOTODOTODOTODO'):
124 """Make a new tlsdata structure, based the fields that may be supplied
125 as flags, or otherwise as defaults. Note that the field "local" is
126 renamed to "local_flags" for reasons of clarity. This helper function
127 returns a tlsdata structure or raises an exception.
129 tlsdata = starttls_data ()
130 if ctlkey is not None:
131 tlsdata.ctlkey = ctlkey
132 tlsdata.service = service
133 tlsdata.localid = localid
134 tlsdata.remoteid = remoteid
135 tlsdata.flags = flags
136 tlsdata.local = local_flags
137 tlsdata.ipproto = ipproto
138 tlsdata.streamid = streamid
139 tlsdata.timeout = timeout
143 """The tlspool.Connection class wraps around a connection to be protected
144 by the TLS Pool. It uses the global socket for attaching to the
145 TLS Pool, but the individual instances of this class do represent
146 individual connections managed by the TLS Pool.
147 New instances can already collect a large number of parameters
148 that end up in the tlsdata structure of tlspool_starttls(),
149 but these values may also be created through getters/setters.
150 Some values have reasonable defaults, but some must have been
151 set before invoking the starttls() method on the instance.
152 The tlsdata fields all have defaults, as specified under
153 tlspool.make_tlsdata().
156 def __init__ (self, cryptsocket, plainsocket=None, **tlsdata):
157 self.cryptsk = cryptsocket
158 self.cryptfd = cryptsocket.fileno ()
159 self.plainsk = plainsocket
160 self.plainfd = plainsocket.fileno () if plainsocket else -1
161 self.tlsdata = make_tlsdata (**tlsdata)
164 assert (self.plainsk is not None)
165 assert (self.plainfd >= 0)
166 self.plainsk.close ()
170 def tlsdata_get (self, tlsvar):
171 return self.tlsdata [tlsvar]
173 def tlsdata_set (self, tlsvar, value):
174 self.tlsdata [tlsvar] = value
177 """Initiate a TLS connection with the current settings, as
178 provided during instantiation or through getter/setter
179 access afterwards. The variables that are required at
180 this point are service and, already obliged when making
181 a new instance, cryptfd.
183 assert (self.cryptsk is not None)
184 assert (self.cryptfd >= 0)
185 assert (self.tlsdata.service != '')
187 af = self.cryptsk.family
191 if self.cryptsk.proto in [socket.IPPROTO_UDP]:
192 socktp = socket.SOCK_DGRAM
193 elif self.cryptsk.proto in [socket.IPPROTO_SCTP]:
194 socktp = socket.SOCK_SEQPACKET
196 socktp = socket.SOCK_STREAM
198 socktp = socket.SOCK_STREAM
199 plainsockptr = socket_data ()
200 plainsockptr.unix_socket = self.plainfd
201 # Provide None for the callback function, SWIG won't support it
202 # We might at some point desire a library of C routine options?
203 rv = _starttls (self.cryptfd, self.tlsdata, plainsockptr, None)
208 _tlspool.raise_errno ()
209 if self.plainsk is None:
210 self.plainfd = plainsockptr.unix_socket
211 self.plainsk = socket.fromfd (self.plainfd, af, socktp)
214 def prng (self, length, label, ctxvalue=None):
215 """Produce length bytes of randomness from the master key, after
216 mixing it with the label and optional context value in ctxvalue.
217 The procedure has been described in RFC 5705.
218 #TODO# Find a way to return the random bytes, and use the length
221 assert (1 <= len (label) <= 254)
222 assert (1 <= len (ctxvalue or 'X') <= 254)
224 # buf.in1_len = len (label)
225 # buf.in2_len = len (ctxvalue) if ctxvalue is not None else 255
226 # buf.prng_len = length
227 rv = _prng (label, ctxvalue, length, buf.buffer, self.tlsdata.ctlkey)
229 _tlspool.raise_errno ()
231 return buf.buffer [:length]
233 def control_detach (self):
234 """Detach control of this connection. Although the connection
235 itself will still be available, control over it is diminished
236 and its continuation is no longer dependent on the current
237 connection. You may need to pass tlsdata.ctlkey to another
238 process, or use control_reattach(), before this is reversed
239 in this process or another.
241 _control_detach (self.tlsdata.ctlkey)
243 def control_reattach (self, ctlkey=None):
244 """Reattach control of this connection. The connection may have
245 called control_detach() in this process or another. To help
246 with the latter case, its tlsdata.ctlkey must have been moved
249 _control_reattach (self.tlsdata.ctlkey)
252 """The SecurityMixIn class can be added as a subclass before a
253 (subclass of) SocketServer.BaseServer and it adds the facilities
254 of starttls(), startgss() and startssh() which add security through
255 one of the mechanisms. In addition, have_xxx() can be used to
256 query in advance if startxxx() should be doable with the present
257 combination of TLS Pool and client code.
259 Set a tlsdata field in the subclass, using the tlspool.make_tlsdata()
260 helper function, to bootstrap the same kind of behaviour on all
261 clients for which this class will be instantiated. Such a tlsdata
262 class variable will automatically be cloned into instances.
265 from tlspool import SecurityMixIn
266 from SocketServer import BaseHandler
268 class MyHandler (SecurityMixIn, BaseHandler):
270 tlsdata = make_tlsdata (service=...)
276 def handle_secure (self):
279 Alternatively, you can setup the tlsdata structure, or any part of it,
280 at a later time, through the tlsdata variable that will then be
281 instantiated during object initialisation. Any such changes to fields
282 must be completed before invoking starttls() on this object.
289 if self.tlsdata is None:
290 self.tlsdata = make_tlsdata ()
293 """Check whether STARTTLS is supported on the current TLS Pool"""
294 if self._pingdata is None:
295 self._pingdata = ping ()
296 return (self._pingdata [1] & PIOF_FACILITY_STARTTLS) != 0
299 """Check whether STARTSSH is supported on the current TLS Pool"""
300 if self._pingdata is None:
301 self._pingdata = ping ()
302 return (self._pingdata [1] & PIOF_FACILITY_STARTSSH) != 0
305 """Check whether STARTGSS is supported on the current TLS Pool"""
306 if self._pingdata is None:
307 self._pingdata = ping ()
308 return (self._pingdata [1] & PIOF_FACILITY_STARTGSS) != 0
311 """Modify the current socket to make it a TLS socket. Use the
312 tlsdata as currently setup (see class-level documentation).
313 Afterwards, call handle_secure() to start from scratch with
314 a secure connection. Also see the man page on the underlying
315 C library call, tlspool_starttls(3).
317 Some protocols start TLS immediately, for instance HTTPS;
318 for such protocols, the handle() method would immediately
319 call starttls() and the actual handler code would move
320 into secure_handle().
322 Other protocols, such as XMPP and IMAP, start in plaintext
323 and exchange pleasantries until they agree on running TLS.
324 This is the point where starttls() can be invoked.
326 The methods startssh() and startgss() are place holders for
327 future alternatives to start other security wrappers than
328 TLS, after negotiating them in a manner similar to STARTTLS.
330 if type (self.request) == tuple:
331 sox = self.request [1]
334 assert (type (sox) == socket._socketobject)
340 if sox.proto in [socket.IPPROTO_UDP]:
341 socktp = socket.SOCK_DGRAM
342 elif sox.proto in [socket.IPPROTO_SCTP]:
343 socktp = socket.SOCK_SEQPACKET
345 socktp = socket.SOCK_STREAM
347 socktp = socket.SOCK_STREAM
348 plainsockptr = socket_data ()
349 plainsockptr.unix_socket = -1
350 rv = _starttls (sox.fileno (), self.tlsdata, plainsockptr, None)
352 _tlspool.raise_errno ()
353 assert (plainsockptr.unix_socket >= 0)
354 sox2 = socket.fromfd (plainsockptr.unix_socket, af, socktp)
355 if type (self.request) == tuple:
356 self.request [1] = sox2
359 self.handle_secure ()
363 raise NotImplementedError ("Python wrapper does not implement STARTSSH")
366 raise NotImplementedError ("Python wrapper does not implement STARTGSS")
369 """When not overridden, the handle() method replaces the one in
370 later-mentioned classes in the inheritance structure. This
371 means that this is the default behaviour when the SecureMixIn
372 precedes the handler class. This particular version of handle()
373 does nothing but invoke starttls(), which in turn invokes
374 handle_secure() after the TLS handshake has succeeded.
378 def handle_secure (self):
379 """This method may be overridden to handle the secure part of the
380 connection, after starttls() has been called from within
381 handle(). This function is special in the sense that it may
382 refer to self.tlsdata and rely on the localid and remoteid
383 as being negotiated over TLS.
385 Since any prior actions in handle() are usually unauthenticated,
386 it is common to start from scratch with the protocol. The secure
387 layer however, tends to enable more features, such as blunt
388 password submission and, perhaps, privileged operations available
389 to the authenticated self.tlsdata.remoteid user.
391 As an example, if the handler class is BaseHTTPRequestHandler,
392 its handle() method could be invoked on the secured content
393 (possibly after authorisation) with an override as follows:
395 def handle_secure (self):
396 BaseHTTPRequestHandler.handle (self)