/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Teddy Hogeborn
  • Date: 2015-03-10 18:03:38 UTC
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
    except ImportError:
89
89
        SO_BINDTODEVICE = None
90
90
 
91
 
version = "1.6.8"
 
91
if sys.version_info.major == 2:
 
92
    str = unicode
 
93
 
 
94
version = "1.6.9"
92
95
stored_state_file = "clients.pickle"
93
96
 
94
97
logger = logging.getLogger()
272
275
        self.bus = bus
273
276
        self.entry_group_state_changed_match = None
274
277
    
275
 
    def rename(self):
 
278
    def rename(self, remove=True):
276
279
        """Derived from the Avahi example code"""
277
280
        if self.rename_count >= self.max_renames:
278
281
            logger.critical("No suitable Zeroconf service name found"
279
282
                            " after %i retries, exiting.",
280
283
                            self.rename_count)
281
284
            raise AvahiServiceError("Too many renames")
282
 
        self.name = unicode(self.server
283
 
                            .GetAlternativeServiceName(self.name))
 
285
        self.name = str(self.server
 
286
                        .GetAlternativeServiceName(self.name))
 
287
        self.rename_count += 1
284
288
        logger.info("Changing Zeroconf service name to %r ...",
285
289
                    self.name)
286
 
        self.remove()
 
290
        if remove:
 
291
            self.remove()
287
292
        try:
288
293
            self.add()
289
294
        except dbus.exceptions.DBusException as error:
290
 
            logger.critical("D-Bus Exception", exc_info=error)
291
 
            self.cleanup()
292
 
            os._exit(1)
293
 
        self.rename_count += 1
 
295
            if (error.get_dbus_name()
 
296
                == "org.freedesktop.Avahi.CollisionError"):
 
297
                logger.info("Local Zeroconf service name collision.")
 
298
                return self.rename(remove=False)
 
299
            else:
 
300
                logger.critical("D-Bus Exception", exc_info=error)
 
301
                self.cleanup()
 
302
                os._exit(1)
294
303
    
295
304
    def remove(self):
296
305
        """Derived from the Avahi example code"""
334
343
            self.rename()
335
344
        elif state == avahi.ENTRY_GROUP_FAILURE:
336
345
            logger.critical("Avahi: Error in group state changed %s",
337
 
                            unicode(error))
 
346
                            str(error))
338
347
            raise AvahiGroupError("State changed: {!s}"
339
348
                                  .format(error))
340
349
    
388
397
 
389
398
 
390
399
class AvahiServiceToSyslog(AvahiService):
391
 
    def rename(self):
 
400
    def rename(self, *args, **kwargs):
392
401
        """Add the new name to the syslog messages"""
393
 
        ret = AvahiService.rename(self)
 
402
        ret = AvahiService.rename(self, *args, **kwargs)
394
403
        syslogger.setFormatter(logging.Formatter
395
404
                               ('Mandos ({}) [%(process)d]:'
396
405
                                ' %(levelname)s: %(message)s'
478
487
            client["enabled"] = config.getboolean(client_name,
479
488
                                                  "enabled")
480
489
            
 
490
            # Uppercase and remove spaces from fingerprint for later
 
491
            # comparison purposes with return value from the
 
492
            # fingerprint() function
481
493
            client["fingerprint"] = (section["fingerprint"].upper()
482
494
                                     .replace(" ", ""))
483
495
            if "secret" in section:
525
537
            self.expires = None
526
538
        
527
539
        logger.debug("Creating client %r", self.name)
528
 
        # Uppercase and remove spaces from fingerprint for later
529
 
        # comparison purposes with return value from the fingerprint()
530
 
        # function
531
540
        logger.debug("  Fingerprint: %s", self.fingerprint)
532
541
        self.created = settings.get("created",
533
542
                                    datetime.datetime.utcnow())
685
694
        if self.checker is None:
686
695
            # Escape attributes for the shell
687
696
            escaped_attrs = { attr:
688
 
                                  re.escape(unicode(getattr(self,
689
 
                                                            attr)))
 
697
                                  re.escape(str(getattr(self, attr)))
690
698
                              for attr in self.runtime_expansions }
691
699
            try:
692
700
                command = self.checker_command % escaped_attrs
811
819
    """Decorator to annotate D-Bus methods, signals or properties
812
820
    Usage:
813
821
    
 
822
    @dbus_annotations({"org.freedesktop.DBus.Deprecated": "true",
 
823
                       "org.freedesktop.DBus.Property."
 
824
                       "EmitsChangedSignal": "false"})
814
825
    @dbus_service_property("org.example.Interface", signature="b",
815
826
                           access="r")
816
 
    @dbus_annotations({{"org.freedesktop.DBus.Deprecated": "true",
817
 
                        "org.freedesktop.DBus.Property."
818
 
                        "EmitsChangedSignal": "false"})
819
827
    def Property_dbus_property(self):
820
828
        return dbus.Boolean(False)
821
829
    """
944
952
                                           value.variant_level+1)
945
953
        return dbus.Dictionary(properties, signature="sv")
946
954
    
 
955
    @dbus.service.signal(dbus.PROPERTIES_IFACE, signature="sa{sv}as")
 
956
    def PropertiesChanged(self, interface_name, changed_properties,
 
957
                          invalidated_properties):
 
958
        """Standard D-Bus PropertiesChanged() signal, see D-Bus
 
959
        standard.
 
960
        """
 
961
        pass
 
962
    
947
963
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
948
964
                         out_signature="s",
949
965
                         path_keyword='object_path',
1216
1232
    runtime_expansions = (Client.runtime_expansions
1217
1233
                          + ("dbus_object_path",))
1218
1234
    
 
1235
    _interface = "se.recompile.Mandos.Client"
 
1236
    
1219
1237
    # dbus.service.Object doesn't use super(), so we can't either.
1220
1238
    
1221
1239
    def __init__(self, bus = None, *args, **kwargs):
1223
1241
        Client.__init__(self, *args, **kwargs)
1224
1242
        # Only now, when this client is initialized, can it show up on
1225
1243
        # the D-Bus
1226
 
        client_object_name = unicode(self.name).translate(
 
1244
        client_object_name = str(self.name).translate(
1227
1245
            {ord("."): ord("_"),
1228
1246
             ord("-"): ord("_")})
1229
1247
        self.dbus_object_path = (dbus.ObjectPath
1233
1251
    
1234
1252
    def notifychangeproperty(transform_func,
1235
1253
                             dbus_name, type_func=lambda x: x,
1236
 
                             variant_level=1):
 
1254
                             variant_level=1, invalidate_only=False,
 
1255
                             _interface=_interface):
1237
1256
        """ Modify a variable so that it's a property which announces
1238
1257
        its changes to DBus.
1239
1258
        
1250
1269
                if (not hasattr(self, attrname) or
1251
1270
                    type_func(getattr(self, attrname, None))
1252
1271
                    != type_func(value)):
1253
 
                    dbus_value = transform_func(type_func(value),
1254
 
                                                variant_level
1255
 
                                                =variant_level)
1256
 
                    self.PropertyChanged(dbus.String(dbus_name),
1257
 
                                         dbus_value)
 
1272
                    if invalidate_only:
 
1273
                        self.PropertiesChanged(_interface,
 
1274
                                               dbus.Dictionary(),
 
1275
                                               dbus.Array
 
1276
                                               ((dbus_name,)))
 
1277
                    else:
 
1278
                        dbus_value = transform_func(type_func(value),
 
1279
                                                    variant_level
 
1280
                                                    =variant_level)
 
1281
                        self.PropertyChanged(dbus.String(dbus_name),
 
1282
                                             dbus_value)
 
1283
                        self.PropertiesChanged(_interface,
 
1284
                                               dbus.Dictionary({
 
1285
                                    dbus.String(dbus_name):
 
1286
                                        dbus_value }), dbus.Array())
1258
1287
            setattr(self, attrname, value)
1259
1288
        
1260
1289
        return property(lambda self: getattr(self, attrname), setter)
1298
1327
                                    lambda td: td.total_seconds()
1299
1328
                                    * 1000)
1300
1329
    checker_command = notifychangeproperty(dbus.String, "Checker")
 
1330
    secret = notifychangeproperty(dbus.ByteArray, "Secret",
 
1331
                                  invalidate_only=True)
1301
1332
    
1302
1333
    del notifychangeproperty
1303
1334
    
1350
1381
        self.send_changedstate()
1351
1382
    
1352
1383
    ## D-Bus methods, signals & properties
1353
 
    _interface = "se.recompile.Mandos.Client"
1354
1384
    
1355
1385
    ## Interfaces
1356
1386
    
1357
 
    @dbus_interface_annotations(_interface)
1358
 
    def _foo(self):
1359
 
        return { "org.freedesktop.DBus.Property.EmitsChangedSignal":
1360
 
                     "false"}
1361
 
    
1362
1387
    ## Signals
1363
1388
    
1364
1389
    # CheckerCompleted - signal
1374
1399
        pass
1375
1400
    
1376
1401
    # PropertyChanged - signal
 
1402
    @dbus_annotations({"org.freedesktop.DBus.Deprecated": "true"})
1377
1403
    @dbus.service.signal(_interface, signature="sv")
1378
1404
    def PropertyChanged(self, property, value):
1379
1405
        "D-Bus signal"
1484
1510
    def Host_dbus_property(self, value=None):
1485
1511
        if value is None:       # get
1486
1512
            return dbus.String(self.host)
1487
 
        self.host = unicode(value)
 
1513
        self.host = str(value)
1488
1514
    
1489
1515
    # Created - property
1490
1516
    @dbus_service_property(_interface, signature="s", access="read")
1588
1614
    def Checker_dbus_property(self, value=None):
1589
1615
        if value is None:       # get
1590
1616
            return dbus.String(self.checker_command)
1591
 
        self.checker_command = unicode(value)
 
1617
        self.checker_command = str(value)
1592
1618
    
1593
1619
    # CheckerRunning - property
1594
1620
    @dbus_service_property(_interface, signature="b",
1650
1676
    def handle(self):
1651
1677
        with contextlib.closing(self.server.child_pipe) as child_pipe:
1652
1678
            logger.info("TCP connection from: %s",
1653
 
                        unicode(self.client_address))
 
1679
                        str(self.client_address))
1654
1680
            logger.debug("Pipe FD: %d",
1655
1681
                         self.server.child_pipe.fileno())
1656
1682
            
2330
2356
                        "port": "",
2331
2357
                        "debug": "False",
2332
2358
                        "priority":
2333
 
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:+SIGN-RSA-SHA224:+SIGN-RSA-RMD160",
 
2359
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
 
2360
                        ":+SIGN-RSA-SHA224:+SIGN-RSA-RMD160",
2334
2361
                        "servicename": "Mandos",
2335
2362
                        "use_dbus": "True",
2336
2363
                        "use_ipv6": "True",
2707
2734
            def GetAllClientsWithProperties(self):
2708
2735
                "D-Bus method"
2709
2736
                return dbus.Dictionary(
2710
 
                    ((c.dbus_object_path, c.GetAll(""))
2711
 
                     for c in tcp_server.clients.itervalues()),
 
2737
                    { c.dbus_object_path: c.GetAll("")
 
2738
                      for c in tcp_server.clients.itervalues() },
2712
2739
                    signature="oa{sv}")
2713
2740
            
2714
2741
            @dbus.service.method(_interface, in_signature="o")