/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: 2018-08-15 09:26:02 UTC
  • Revision ID: teddy@recompile.se-20180815092602-xoyb5s6gf8376i7u
mandos-client: Set system clock if necessary

* plugins.d/mandos-client.c (init_gpgme/import_key): If the system
  clock is not set, or set to january 1970, set the system clock to
  the more plausible value that is the mtime of the key file.  This is
  required by GnuPG to be able to import the keys.  (We can't pass the
  --ignore-time-conflict or the --ignore-valid-from options though
  GPGME.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
115
115
if sys.version_info.major == 2:
116
116
    str = unicode
117
117
 
118
 
version = "1.7.20"
 
118
version = "1.7.19"
119
119
stored_state_file = "clients.pickle"
120
120
 
121
121
logger = logging.getLogger()
514
514
    _library = ctypes.cdll.LoadLibrary(library)
515
515
    del library
516
516
    _need_version = b"3.3.0"
517
 
    _tls_rawpk_version = b"3.6.6"
518
517
 
519
518
    def __init__(self):
520
519
        # Need to use "self" here, since this method is called before
531
530
    E_INTERRUPTED = -52
532
531
    E_AGAIN = -28
533
532
    CRT_OPENPGP = 2
534
 
    CRT_RAWPK = 3
535
533
    CLIENT = 2
536
534
    SHUT_RDWR = 0
537
535
    CRD_CERTIFICATE = 1
538
536
    E_NO_CERTIFICATE_FOUND = -49
539
 
    X509_FMT_DER = 0
540
 
    NO_TICKETS = 1<<10
541
 
    ENABLE_RAWPK = 1<<18
542
 
    CTYPE_PEERS = 3
543
 
    KEYID_USE_SHA256 = 1        # gnutls/x509.h
544
537
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
545
538
 
546
539
    # Types
600
593
    class ClientSession(object):
601
594
        def __init__(self, socket, credentials=None):
602
595
            self._c_object = gnutls.session_t()
603
 
            gnutls_flags = gnutls.CLIENT
604
 
            if gnutls.check_version("3.5.6"):
605
 
                gnutls_flags |= gnutls.NO_TICKETS
606
 
            if gnutls.has_rawpk:
607
 
                gnutls_flags |= gnutls.ENABLE_RAWPK
608
 
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
609
 
            del gnutls_flags
 
596
            gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
610
597
            gnutls.set_default_priority(self._c_object)
611
598
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
612
599
            gnutls.handshake_set_private_extensions(self._c_object,
744
731
    check_version.argtypes = [ctypes.c_char_p]
745
732
    check_version.restype = ctypes.c_char_p
746
733
 
747
 
    has_rawpk = bool(check_version(_tls_rawpk_version))
748
 
 
749
 
    if has_rawpk:
750
 
        # Types
751
 
        class pubkey_st(ctypes.Structure):
752
 
            _fields = []
753
 
        pubkey_t = ctypes.POINTER(pubkey_st)
754
 
 
755
 
        x509_crt_fmt_t = ctypes.c_int
756
 
 
757
 
        # All the function declarations below are from gnutls/abstract.h
758
 
        pubkey_init = _library.gnutls_pubkey_init
759
 
        pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)]
760
 
        pubkey_init.restype = _error_code
761
 
 
762
 
        pubkey_import = _library.gnutls_pubkey_import
763
 
        pubkey_import.argtypes = [pubkey_t, ctypes.POINTER(datum_t),
764
 
                                  x509_crt_fmt_t]
765
 
        pubkey_import.restype = _error_code
766
 
 
767
 
        pubkey_get_key_id = _library.gnutls_pubkey_get_key_id
768
 
        pubkey_get_key_id.argtypes = [pubkey_t, ctypes.c_int,
769
 
                                      ctypes.POINTER(ctypes.c_ubyte),
770
 
                                      ctypes.POINTER(ctypes.c_size_t)]
771
 
        pubkey_get_key_id.restype = _error_code
772
 
 
773
 
        pubkey_deinit = _library.gnutls_pubkey_deinit
774
 
        pubkey_deinit.argtypes = [pubkey_t]
775
 
        pubkey_deinit.restype = None
776
 
    else:
777
 
        # All the function declarations below are from gnutls/openpgp.h
778
 
 
779
 
        openpgp_crt_init = _library.gnutls_openpgp_crt_init
780
 
        openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
781
 
        openpgp_crt_init.restype = _error_code
782
 
 
783
 
        openpgp_crt_import = _library.gnutls_openpgp_crt_import
784
 
        openpgp_crt_import.argtypes = [openpgp_crt_t,
785
 
                                       ctypes.POINTER(datum_t),
786
 
                                       openpgp_crt_fmt_t]
787
 
        openpgp_crt_import.restype = _error_code
788
 
 
789
 
        openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
790
 
        openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
791
 
                                            ctypes.POINTER(ctypes.c_uint)]
792
 
        openpgp_crt_verify_self.restype = _error_code
793
 
 
794
 
        openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
795
 
        openpgp_crt_deinit.argtypes = [openpgp_crt_t]
796
 
        openpgp_crt_deinit.restype = None
797
 
 
798
 
        openpgp_crt_get_fingerprint = (
799
 
            _library.gnutls_openpgp_crt_get_fingerprint)
800
 
        openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
801
 
                                                ctypes.c_void_p,
802
 
                                                ctypes.POINTER(
803
 
                                                    ctypes.c_size_t)]
804
 
        openpgp_crt_get_fingerprint.restype = _error_code
805
 
 
806
 
    if check_version("3.6.4"):
807
 
        certificate_type_get2 = _library.gnutls_certificate_type_get2
808
 
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
809
 
        certificate_type_get2.restype = _error_code
 
734
    # All the function declarations below are from gnutls/openpgp.h
 
735
 
 
736
    openpgp_crt_init = _library.gnutls_openpgp_crt_init
 
737
    openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
 
738
    openpgp_crt_init.restype = _error_code
 
739
 
 
740
    openpgp_crt_import = _library.gnutls_openpgp_crt_import
 
741
    openpgp_crt_import.argtypes = [openpgp_crt_t,
 
742
                                   ctypes.POINTER(datum_t),
 
743
                                   openpgp_crt_fmt_t]
 
744
    openpgp_crt_import.restype = _error_code
 
745
 
 
746
    openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
747
    openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
748
                                        ctypes.POINTER(ctypes.c_uint)]
 
749
    openpgp_crt_verify_self.restype = _error_code
 
750
 
 
751
    openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
 
752
    openpgp_crt_deinit.argtypes = [openpgp_crt_t]
 
753
    openpgp_crt_deinit.restype = None
 
754
 
 
755
    openpgp_crt_get_fingerprint = (
 
756
        _library.gnutls_openpgp_crt_get_fingerprint)
 
757
    openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
 
758
                                            ctypes.c_void_p,
 
759
                                            ctypes.POINTER(
 
760
                                                ctypes.c_size_t)]
 
761
    openpgp_crt_get_fingerprint.restype = _error_code
810
762
 
811
763
    # Remove non-public functions
812
764
    del _error_code, _retry_on_error
848
800
    disable_initiator_tag: a GLib event source tag, or None
849
801
    enabled:    bool()
850
802
    fingerprint: string (40 or 32 hexadecimal digits); used to
851
 
                 uniquely identify an OpenPGP client
852
 
    key_id: string (64 hexadecimal digits); used to uniquely identify
853
 
            a client using raw public keys
 
803
                 uniquely identify the client
854
804
    host:       string; available for use by the checker command
855
805
    interval:   datetime.timedelta(); How often to start a new checker
856
806
    last_approval_request: datetime.datetime(); (UTC) or None
874
824
    """
875
825
 
876
826
    runtime_expansions = ("approval_delay", "approval_duration",
877
 
                          "created", "enabled", "expires", "key_id",
 
827
                          "created", "enabled", "expires",
878
828
                          "fingerprint", "host", "interval",
879
829
                          "last_approval_request", "last_checked_ok",
880
830
                          "last_enabled", "name", "timeout")
910
860
            client["enabled"] = config.getboolean(client_name,
911
861
                                                  "enabled")
912
862
 
913
 
            # Uppercase and remove spaces from key_id and fingerprint
914
 
            # for later comparison purposes with return value from the
915
 
            # key_id() and fingerprint() functions
916
 
            client["key_id"] = (section.get("key_id", "").upper()
917
 
                                .replace(" ", ""))
 
863
            # Uppercase and remove spaces from fingerprint for later
 
864
            # comparison purposes with return value from the
 
865
            # fingerprint() function
918
866
            client["fingerprint"] = (section["fingerprint"].upper()
919
867
                                     .replace(" ", ""))
920
868
            if "secret" in section:
964
912
            self.expires = None
965
913
 
966
914
        logger.debug("Creating client %r", self.name)
967
 
        logger.debug("  Key ID: %s", self.key_id)
968
915
        logger.debug("  Fingerprint: %s", self.fingerprint)
969
916
        self.created = settings.get("created",
970
917
                                    datetime.datetime.utcnow())
2052
1999
    def Name_dbus_property(self):
2053
2000
        return dbus.String(self.name)
2054
2001
 
2055
 
    # KeyID - property
2056
 
    @dbus_annotations(
2057
 
        {"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
2058
 
    @dbus_service_property(_interface, signature="s", access="read")
2059
 
    def KeyID_dbus_property(self):
2060
 
        return dbus.String(self.key_id)
2061
 
 
2062
2002
    # Fingerprint - property
2063
2003
    @dbus_annotations(
2064
2004
        {"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
2220
2160
 
2221
2161
 
2222
2162
class ProxyClient(object):
2223
 
    def __init__(self, child_pipe, key_id, fpr, address):
 
2163
    def __init__(self, child_pipe, fpr, address):
2224
2164
        self._pipe = child_pipe
2225
 
        self._pipe.send(('init', key_id, fpr, address))
 
2165
        self._pipe.send(('init', fpr, address))
2226
2166
        if not self._pipe.recv():
2227
 
            raise KeyError(key_id or fpr)
 
2167
            raise KeyError(fpr)
2228
2168
 
2229
2169
    def __getattribute__(self, name):
2230
2170
        if name == '_pipe':
2297
2237
 
2298
2238
            approval_required = False
2299
2239
            try:
2300
 
                if gnutls.has_rawpk:
2301
 
                    fpr = ""
2302
 
                    try:
2303
 
                        key_id = self.key_id(
2304
 
                            self.peer_certificate(session))
2305
 
                    except (TypeError, gnutls.Error) as error:
2306
 
                        logger.warning("Bad certificate: %s", error)
2307
 
                        return
2308
 
                    logger.debug("Key ID: %s", key_id)
2309
 
 
2310
 
                else:
2311
 
                    key_id = ""
2312
 
                    try:
2313
 
                        fpr = self.fingerprint(
2314
 
                            self.peer_certificate(session))
2315
 
                    except (TypeError, gnutls.Error) as error:
2316
 
                        logger.warning("Bad certificate: %s", error)
2317
 
                        return
2318
 
                    logger.debug("Fingerprint: %s", fpr)
2319
 
 
2320
 
                try:
2321
 
                    client = ProxyClient(child_pipe, key_id, fpr,
 
2240
                try:
 
2241
                    fpr = self.fingerprint(
 
2242
                        self.peer_certificate(session))
 
2243
                except (TypeError, gnutls.Error) as error:
 
2244
                    logger.warning("Bad certificate: %s", error)
 
2245
                    return
 
2246
                logger.debug("Fingerprint: %s", fpr)
 
2247
 
 
2248
                try:
 
2249
                    client = ProxyClient(child_pipe, fpr,
2322
2250
                                         self.client_address)
2323
2251
                except KeyError:
2324
2252
                    return
2401
2329
 
2402
2330
    @staticmethod
2403
2331
    def peer_certificate(session):
2404
 
        "Return the peer's certificate as a bytestring"
2405
 
        try:
2406
 
            cert_type = gnutls.certificate_type_get2(session._c_object,
2407
 
                                                     gnutls.CTYPE_PEERS)
2408
 
        except AttributeError:
2409
 
            cert_type = gnutls.certificate_type_get(session._c_object)
2410
 
        if gnutls.has_rawpk:
2411
 
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
2412
 
        else:
2413
 
            valid_cert_types = frozenset((gnutls.CRT_OPENPGP,))
2414
 
        # If not a valid certificate type...
2415
 
        if cert_type not in valid_cert_types:
2416
 
            logger.info("Cert type %r not in %r", cert_type,
2417
 
                        valid_cert_types)
 
2332
        "Return the peer's OpenPGP certificate as a bytestring"
 
2333
        # If not an OpenPGP certificate...
 
2334
        if (gnutls.certificate_type_get(session._c_object)
 
2335
            != gnutls.CRT_OPENPGP):
2418
2336
            # ...return invalid data
2419
2337
            return b""
2420
2338
        list_size = ctypes.c_uint(1)
2428
2346
        return ctypes.string_at(cert.data, cert.size)
2429
2347
 
2430
2348
    @staticmethod
2431
 
    def key_id(certificate):
2432
 
        "Convert a certificate bytestring to a hexdigit key ID"
2433
 
        # New GnuTLS "datum" with the public key
2434
 
        datum = gnutls.datum_t(
2435
 
            ctypes.cast(ctypes.c_char_p(certificate),
2436
 
                        ctypes.POINTER(ctypes.c_ubyte)),
2437
 
            ctypes.c_uint(len(certificate)))
2438
 
        # XXX all these need to be created in the gnutls "module"
2439
 
        # New empty GnuTLS certificate
2440
 
        pubkey = gnutls.pubkey_t()
2441
 
        gnutls.pubkey_init(ctypes.byref(pubkey))
2442
 
        # Import the raw public key into the certificate
2443
 
        gnutls.pubkey_import(pubkey,
2444
 
                             ctypes.byref(datum),
2445
 
                             gnutls.X509_FMT_DER)
2446
 
        # New buffer for the key ID
2447
 
        buf = ctypes.create_string_buffer(32)
2448
 
        buf_len = ctypes.c_size_t(len(buf))
2449
 
        # Get the key ID from the raw public key into the buffer
2450
 
        gnutls.pubkey_get_key_id(pubkey,
2451
 
                                 gnutls.KEYID_USE_SHA256,
2452
 
                                 ctypes.cast(ctypes.byref(buf),
2453
 
                                             ctypes.POINTER(ctypes.c_ubyte)),
2454
 
                                 ctypes.byref(buf_len))
2455
 
        # Deinit the certificate
2456
 
        gnutls.pubkey_deinit(pubkey)
2457
 
 
2458
 
        # Convert the buffer to a Python bytestring
2459
 
        key_id = ctypes.string_at(buf, buf_len.value)
2460
 
        # Convert the bytestring to hexadecimal notation
2461
 
        hex_key_id = binascii.hexlify(key_id).upper()
2462
 
        return hex_key_id
2463
 
 
2464
 
    @staticmethod
2465
2349
    def fingerprint(openpgp):
2466
2350
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
2467
2351
        # New GnuTLS "datum" with the OpenPGP public key
2695
2579
        command = request[0]
2696
2580
 
2697
2581
        if command == 'init':
2698
 
            key_id = request[1].decode("ascii")
2699
 
            fpr = request[2].decode("ascii")
2700
 
            address = request[3]
 
2582
            fpr = request[1].decode("ascii")
 
2583
            address = request[2]
2701
2584
 
2702
2585
            for c in self.clients.values():
2703
 
                if key_id and c.key_id == key_id:
2704
 
                    client = c
2705
 
                    break
2706
 
                if fpr and c.fingerprint == fpr:
 
2586
                if c.fingerprint == fpr:
2707
2587
                    client = c
2708
2588
                    break
2709
2589
            else:
2710
 
                logger.info("Client not found for key ID: %s, address"
2711
 
                            ": %s", key_id or fpr, address)
 
2590
                logger.info("Client not found for fingerprint: %s, ad"
 
2591
                            "dress: %s", fpr, address)
2712
2592
                if self.use_dbus:
2713
2593
                    # Emit D-Bus signal
2714
 
                    mandos_dbus_service.ClientNotFound(key_id or fpr,
 
2594
                    mandos_dbus_service.ClientNotFound(fpr,
2715
2595
                                                       address[0])
2716
2596
                parent_pipe.send(False)
2717
2597
                return False
2980
2860
        sys.exit(os.EX_OK if fail_count == 0 else 1)
2981
2861
 
2982
2862
    # Default values for config file for server-global settings
2983
 
    if gnutls.has_rawpk:
2984
 
        priority = ("SECURE128:!CTYPE-X.509:+CTYPE-RAWPK:!RSA"
2985
 
                    ":!VERS-ALL:+VERS-TLS1.3:%PROFILE_ULTRA")
2986
 
    else:
2987
 
        priority = ("SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
2988
 
                    ":+SIGN-DSA-SHA256")
2989
2863
    server_defaults = {"interface": "",
2990
2864
                       "address": "",
2991
2865
                       "port": "",
2992
2866
                       "debug": "False",
2993
 
                       "priority": priority,
 
2867
                       "priority":
 
2868
                       "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
 
2869
                       ":+SIGN-DSA-SHA256",
2994
2870
                       "servicename": "Mandos",
2995
2871
                       "use_dbus": "True",
2996
2872
                       "use_ipv6": "True",
3001
2877
                       "foreground": "False",
3002
2878
                       "zeroconf": "True",
3003
2879
                       }
3004
 
    del priority
3005
2880
 
3006
2881
    # Parse config file for server-global settings
3007
2882
    server_config = configparser.SafeConfigParser(server_defaults)
3251
3126
                        for k in ("name", "host"):
3252
3127
                            if isinstance(value[k], bytes):
3253
3128
                                value[k] = value[k].decode("utf-8")
3254
 
                        if not value.has_key("key_id"):
3255
 
                            value["key_id"] = ""
3256
 
                        elif not value.has_key("fingerprint"):
3257
 
                            value["fingerprint"] = ""
3258
3129
                    #  old_client_settings
3259
3130
                    # .keys()
3260
3131
                    old_client_settings = {
3397
3268
                pass
3398
3269
 
3399
3270
            @dbus.service.signal(_interface, signature="ss")
3400
 
            def ClientNotFound(self, key_id, address):
 
3271
            def ClientNotFound(self, fingerprint, address):
3401
3272
                "D-Bus signal"
3402
3273
                pass
3403
3274