/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: 2016-02-28 12:29:12 UTC
  • Revision ID: teddy@recompile.se-20160228122912-6yxw70vq8oze7ogc
Remove version specific packages from Debian dependencies.

* debian/control (Source: mandos/Build-Depends-Indep): Remove
  "python2.7", "python2.7-dbus", "python2.7-avahi", and
  "python2.7-gobject"; replace with "python (= 2.7)", "python-dbus",
  "python-avahi", "python-gobject".

Thanks: Scott Kitterman <debian@kitterman.com>
Closes: #811159

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
import argparse
45
45
import datetime
46
46
import errno
47
 
import gnutls.connection
48
 
import gnutls.errors
49
 
import gnutls.library.functions
50
 
import gnutls.library.constants
51
 
import gnutls.library.types
52
47
try:
53
48
    import ConfigParser as configparser
54
49
except ImportError:
434
429
            .format(self.name)))
435
430
        return ret
436
431
 
 
432
# Pretend that we have a GnuTLS module
 
433
class GnuTLS(object):
 
434
    """This isn't so much a class as it is a module-like namespace.
 
435
    It is instantiated once, and simulates having a GnuTLS module."""
 
436
    
 
437
    _library = ctypes.cdll.LoadLibrary(
 
438
        ctypes.util.find_library("gnutls"))
 
439
    _need_version = "3.3.0"
 
440
    def __init__(self):
 
441
        # Need to use class name "GnuTLS" here, since this method is
 
442
        # called before the assignment to the "gnutls" global variable
 
443
        # happens.
 
444
        if GnuTLS.check_version(self._need_version) is None:
 
445
            raise GnuTLS.Error("Needs GnuTLS {} or later"
 
446
                               .format(self._need_version))
 
447
    
 
448
    # Unless otherwise indicated, the constants and types below are
 
449
    # all from the gnutls/gnutls.h C header file.
 
450
    
 
451
    # Constants
 
452
    E_SUCCESS = 0
 
453
    E_INTERRUPTED = -52
 
454
    E_AGAIN = -28
 
455
    CRT_OPENPGP = 2
 
456
    CLIENT = 2
 
457
    SHUT_RDWR = 0
 
458
    CRD_CERTIFICATE = 1
 
459
    E_NO_CERTIFICATE_FOUND = -49
 
460
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
 
461
    
 
462
    # Types
 
463
    class session_int(ctypes.Structure):
 
464
        _fields_ = []
 
465
    session_t = ctypes.POINTER(session_int)
 
466
    class certificate_credentials_st(ctypes.Structure):
 
467
        _fields_ = []
 
468
    certificate_credentials_t = ctypes.POINTER(
 
469
        certificate_credentials_st)
 
470
    certificate_type_t = ctypes.c_int
 
471
    class datum_t(ctypes.Structure):
 
472
        _fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
 
473
                    ('size', ctypes.c_uint)]
 
474
    class openpgp_crt_int(ctypes.Structure):
 
475
        _fields_ = []
 
476
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
 
477
    openpgp_crt_fmt_t = ctypes.c_int # gnutls/openpgp.h
 
478
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
 
479
    credentials_type_t = ctypes.c_int # 
 
480
    transport_ptr_t = ctypes.c_void_p
 
481
    close_request_t = ctypes.c_int
 
482
    
 
483
    # Exceptions
 
484
    class Error(Exception):
 
485
        # We need to use the class name "GnuTLS" here, since this
 
486
        # exception might be raised from within GnuTLS.__init__,
 
487
        # which is called before the assignment to the "gnutls"
 
488
        # global variable has happened.
 
489
        def __init__(self, message = None, code = None, args=()):
 
490
            # Default usage is by a message string, but if a return
 
491
            # code is passed, convert it to a string with
 
492
            # gnutls.strerror()
 
493
            self.code = code
 
494
            if message is None and code is not None:
 
495
                message = GnuTLS.strerror(code)
 
496
            return super(GnuTLS.Error, self).__init__(
 
497
                message, *args)
 
498
    
 
499
    class CertificateSecurityError(Error):
 
500
        pass
 
501
    
 
502
    # Classes
 
503
    class Credentials(object):
 
504
        def __init__(self):
 
505
            self._c_object = gnutls.certificate_credentials_t()
 
506
            gnutls.certificate_allocate_credentials(
 
507
                ctypes.byref(self._c_object))
 
508
            self.type = gnutls.CRD_CERTIFICATE
 
509
        
 
510
        def __del__(self):
 
511
            gnutls.certificate_free_credentials(self._c_object)
 
512
    
 
513
    class ClientSession(object):
 
514
        def __init__(self, socket, credentials = None):
 
515
            self._c_object = gnutls.session_t()
 
516
            gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
 
517
            gnutls.set_default_priority(self._c_object)
 
518
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
 
519
            gnutls.handshake_set_private_extensions(self._c_object,
 
520
                                                    True)
 
521
            self.socket = socket
 
522
            if credentials is None:
 
523
                credentials = gnutls.Credentials()
 
524
            gnutls.credentials_set(self._c_object, credentials.type,
 
525
                                   ctypes.cast(credentials._c_object,
 
526
                                               ctypes.c_void_p))
 
527
            self.credentials = credentials
 
528
        
 
529
        def __del__(self):
 
530
            gnutls.deinit(self._c_object)
 
531
        
 
532
        def handshake(self):
 
533
            return gnutls.handshake(self._c_object)
 
534
        
 
535
        def send(self, data):
 
536
            data = bytes(data)
 
537
            data_len = len(data)
 
538
            while data_len > 0:
 
539
                data_len -= gnutls.record_send(self._c_object,
 
540
                                               data[-data_len:],
 
541
                                               data_len)
 
542
        
 
543
        def bye(self):
 
544
            return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
 
545
    
 
546
    # Error handling functions
 
547
    def _error_code(result):
 
548
        """A function to raise exceptions on errors, suitable
 
549
        for the 'restype' attribute on ctypes functions"""
 
550
        if result >= 0:
 
551
            return result
 
552
        if result == gnutls.E_NO_CERTIFICATE_FOUND:
 
553
            raise gnutls.CertificateSecurityError(code = result)
 
554
        raise gnutls.Error(code = result)
 
555
    
 
556
    def _retry_on_error(result, func, arguments):
 
557
        """A function to retry on some errors, suitable
 
558
        for the 'errcheck' attribute on ctypes functions"""
 
559
        while result < 0:
 
560
            if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
 
561
                return _error_code(result)
 
562
            result = func(*arguments)
 
563
        return result
 
564
    
 
565
    # Unless otherwise indicated, the function declarations below are
 
566
    # all from the gnutls/gnutls.h C header file.
 
567
    
 
568
    # Functions
 
569
    priority_set_direct = _library.gnutls_priority_set_direct
 
570
    priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
 
571
                                    ctypes.POINTER(ctypes.c_char_p)]
 
572
    priority_set_direct.restype = _error_code
 
573
    
 
574
    init = _library.gnutls_init
 
575
    init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
 
576
    init.restype = _error_code
 
577
    
 
578
    set_default_priority = _library.gnutls_set_default_priority
 
579
    set_default_priority.argtypes = [session_t]
 
580
    set_default_priority.restype = _error_code
 
581
    
 
582
    record_send = _library.gnutls_record_send
 
583
    record_send.argtypes = [session_t, ctypes.c_void_p,
 
584
                            ctypes.c_size_t]
 
585
    record_send.restype = ctypes.c_ssize_t
 
586
    record_send.errcheck = _retry_on_error
 
587
    
 
588
    certificate_allocate_credentials = (
 
589
        _library.gnutls_certificate_allocate_credentials)
 
590
    certificate_allocate_credentials.argtypes = [
 
591
        ctypes.POINTER(certificate_credentials_t)]
 
592
    certificate_allocate_credentials.restype = _error_code
 
593
    
 
594
    certificate_free_credentials = (
 
595
        _library.gnutls_certificate_free_credentials)
 
596
    certificate_free_credentials.argtypes = [certificate_credentials_t]
 
597
    certificate_free_credentials.restype = None
 
598
    
 
599
    handshake_set_private_extensions = (
 
600
        _library.gnutls_handshake_set_private_extensions)
 
601
    handshake_set_private_extensions.argtypes = [session_t,
 
602
                                                 ctypes.c_int]
 
603
    handshake_set_private_extensions.restype = None
 
604
    
 
605
    credentials_set = _library.gnutls_credentials_set
 
606
    credentials_set.argtypes = [session_t, credentials_type_t,
 
607
                                ctypes.c_void_p]
 
608
    credentials_set.restype = _error_code
 
609
    
 
610
    strerror = _library.gnutls_strerror
 
611
    strerror.argtypes = [ctypes.c_int]
 
612
    strerror.restype = ctypes.c_char_p
 
613
    
 
614
    certificate_type_get = _library.gnutls_certificate_type_get
 
615
    certificate_type_get.argtypes = [session_t]
 
616
    certificate_type_get.restype = _error_code
 
617
    
 
618
    certificate_get_peers = _library.gnutls_certificate_get_peers
 
619
    certificate_get_peers.argtypes = [session_t,
 
620
                                      ctypes.POINTER(ctypes.c_uint)]
 
621
    certificate_get_peers.restype = ctypes.POINTER(datum_t)
 
622
    
 
623
    global_set_log_level = _library.gnutls_global_set_log_level
 
624
    global_set_log_level.argtypes = [ctypes.c_int]
 
625
    global_set_log_level.restype = None
 
626
    
 
627
    global_set_log_function = _library.gnutls_global_set_log_function
 
628
    global_set_log_function.argtypes = [log_func]
 
629
    global_set_log_function.restype = None
 
630
    
 
631
    deinit = _library.gnutls_deinit
 
632
    deinit.argtypes = [session_t]
 
633
    deinit.restype = None
 
634
    
 
635
    handshake = _library.gnutls_handshake
 
636
    handshake.argtypes = [session_t]
 
637
    handshake.restype = _error_code
 
638
    handshake.errcheck = _retry_on_error
 
639
    
 
640
    transport_set_ptr = _library.gnutls_transport_set_ptr
 
641
    transport_set_ptr.argtypes = [session_t, transport_ptr_t]
 
642
    transport_set_ptr.restype = None
 
643
    
 
644
    bye = _library.gnutls_bye
 
645
    bye.argtypes = [session_t, close_request_t]
 
646
    bye.restype = _error_code
 
647
    bye.errcheck = _retry_on_error
 
648
    
 
649
    check_version = _library.gnutls_check_version
 
650
    check_version.argtypes = [ctypes.c_char_p]
 
651
    check_version.restype = ctypes.c_char_p
 
652
    
 
653
    # All the function declarations below are from gnutls/openpgp.h
 
654
    
 
655
    openpgp_crt_init = _library.gnutls_openpgp_crt_init
 
656
    openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
 
657
    openpgp_crt_init.restype = _error_code
 
658
    
 
659
    openpgp_crt_import = _library.gnutls_openpgp_crt_import
 
660
    openpgp_crt_import.argtypes = [openpgp_crt_t,
 
661
                                   ctypes.POINTER(datum_t),
 
662
                                   openpgp_crt_fmt_t]
 
663
    openpgp_crt_import.restype = _error_code
 
664
    
 
665
    openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
666
    openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
667
                                        ctypes.POINTER(ctypes.c_uint)]
 
668
    openpgp_crt_verify_self.restype = _error_code
 
669
    
 
670
    openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
 
671
    openpgp_crt_deinit.argtypes = [openpgp_crt_t]
 
672
    openpgp_crt_deinit.restype = None
 
673
    
 
674
    openpgp_crt_get_fingerprint = (
 
675
        _library.gnutls_openpgp_crt_get_fingerprint)
 
676
    openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
 
677
                                            ctypes.c_void_p,
 
678
                                            ctypes.POINTER(
 
679
                                                ctypes.c_size_t)]
 
680
    openpgp_crt_get_fingerprint.restype = _error_code
 
681
    
 
682
    # Remove non-public functions
 
683
    del _error_code, _retry_on_error
 
684
# Create the global "gnutls" object, simulating a module
 
685
gnutls = GnuTLS()
 
686
 
437
687
def call_pipe(connection,       # : multiprocessing.Connection
438
688
              func, *args, **kwargs):
439
689
    """This function is meant to be called by multiprocessing.Process
1879
2129
            logger.debug("Pipe FD: %d",
1880
2130
                         self.server.child_pipe.fileno())
1881
2131
            
1882
 
            session = gnutls.connection.ClientSession(
1883
 
                self.request, gnutls.connection.X509Credentials())
1884
 
            
1885
 
            # Note: gnutls.connection.X509Credentials is really a
1886
 
            # generic GnuTLS certificate credentials object so long as
1887
 
            # no X.509 keys are added to it.  Therefore, we can use it
1888
 
            # here despite using OpenPGP certificates.
 
2132
            session = gnutls.ClientSession(self.request)
1889
2133
            
1890
2134
            #priority = ':'.join(("NONE", "+VERS-TLS1.1",
1891
2135
            #                      "+AES-256-CBC", "+SHA1",
1895
2139
            priority = self.server.gnutls_priority
1896
2140
            if priority is None:
1897
2141
                priority = "NORMAL"
1898
 
            gnutls.library.functions.gnutls_priority_set_direct(
1899
 
                session._c_object, priority, None)
 
2142
            gnutls.priority_set_direct(session._c_object, priority,
 
2143
                                       None)
1900
2144
            
1901
2145
            # Start communication using the Mandos protocol
1902
2146
            # Get protocol number
1912
2156
            # Start GnuTLS connection
1913
2157
            try:
1914
2158
                session.handshake()
1915
 
            except gnutls.errors.GNUTLSError as error:
 
2159
            except gnutls.Error as error:
1916
2160
                logger.warning("Handshake failed: %s", error)
1917
2161
                # Do not run session.bye() here: the session is not
1918
2162
                # established.  Just abandon the request.
1924
2168
                try:
1925
2169
                    fpr = self.fingerprint(
1926
2170
                        self.peer_certificate(session))
1927
 
                except (TypeError,
1928
 
                        gnutls.errors.GNUTLSError) as error:
 
2171
                except (TypeError, gnutls.Error) as error:
1929
2172
                    logger.warning("Bad certificate: %s", error)
1930
2173
                    return
1931
2174
                logger.debug("Fingerprint: %s", fpr)
1989
2232
                    else:
1990
2233
                        delay -= time2 - time
1991
2234
                
1992
 
                sent_size = 0
1993
 
                while sent_size < len(client.secret):
1994
 
                    try:
1995
 
                        sent = session.send(client.secret[sent_size:])
1996
 
                    except gnutls.errors.GNUTLSError as error:
1997
 
                        logger.warning("gnutls send failed",
1998
 
                                       exc_info=error)
1999
 
                        return
2000
 
                    logger.debug("Sent: %d, remaining: %d", sent,
2001
 
                                 len(client.secret) - (sent_size
2002
 
                                                       + sent))
2003
 
                    sent_size += sent
 
2235
                try:
 
2236
                    session.send(client.secret)
 
2237
                except gnutls.Error as error:
 
2238
                    logger.warning("gnutls send failed",
 
2239
                                   exc_info = error)
 
2240
                    return
2004
2241
                
2005
2242
                logger.info("Sending secret to %s", client.name)
2006
2243
                # bump the timeout using extended_timeout
2014
2251
                    client.approvals_pending -= 1
2015
2252
                try:
2016
2253
                    session.bye()
2017
 
                except gnutls.errors.GNUTLSError as error:
 
2254
                except gnutls.Error as error:
2018
2255
                    logger.warning("GnuTLS bye failed",
2019
2256
                                   exc_info=error)
2020
2257
    
2022
2259
    def peer_certificate(session):
2023
2260
        "Return the peer's OpenPGP certificate as a bytestring"
2024
2261
        # If not an OpenPGP certificate...
2025
 
        if (gnutls.library.functions.gnutls_certificate_type_get(
2026
 
                session._c_object)
2027
 
            != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
2028
 
            # ...do the normal thing
2029
 
            return session.peer_certificate
 
2262
        if (gnutls.certificate_type_get(session._c_object)
 
2263
            != gnutls.CRT_OPENPGP):
 
2264
            # ...return invalid data
 
2265
            return b""
2030
2266
        list_size = ctypes.c_uint(1)
2031
 
        cert_list = (gnutls.library.functions
2032
 
                     .gnutls_certificate_get_peers
 
2267
        cert_list = (gnutls.certificate_get_peers
2033
2268
                     (session._c_object, ctypes.byref(list_size)))
2034
2269
        if not bool(cert_list) and list_size.value != 0:
2035
 
            raise gnutls.errors.GNUTLSError("error getting peer"
2036
 
                                            " certificate")
 
2270
            raise gnutls.Error("error getting peer certificate")
2037
2271
        if list_size.value == 0:
2038
2272
            return None
2039
2273
        cert = cert_list[0]
2043
2277
    def fingerprint(openpgp):
2044
2278
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
2045
2279
        # New GnuTLS "datum" with the OpenPGP public key
2046
 
        datum = gnutls.library.types.gnutls_datum_t(
 
2280
        datum = gnutls.datum_t(
2047
2281
            ctypes.cast(ctypes.c_char_p(openpgp),
2048
2282
                        ctypes.POINTER(ctypes.c_ubyte)),
2049
2283
            ctypes.c_uint(len(openpgp)))
2050
2284
        # New empty GnuTLS certificate
2051
 
        crt = gnutls.library.types.gnutls_openpgp_crt_t()
2052
 
        gnutls.library.functions.gnutls_openpgp_crt_init(
2053
 
            ctypes.byref(crt))
 
2285
        crt = gnutls.openpgp_crt_t()
 
2286
        gnutls.openpgp_crt_init(ctypes.byref(crt))
2054
2287
        # Import the OpenPGP public key into the certificate
2055
 
        gnutls.library.functions.gnutls_openpgp_crt_import(
2056
 
            crt, ctypes.byref(datum),
2057
 
            gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
 
2288
        gnutls.openpgp_crt_import(crt, ctypes.byref(datum),
 
2289
                                  gnutls.OPENPGP_FMT_RAW)
2058
2290
        # Verify the self signature in the key
2059
2291
        crtverify = ctypes.c_uint()
2060
 
        gnutls.library.functions.gnutls_openpgp_crt_verify_self(
2061
 
            crt, 0, ctypes.byref(crtverify))
 
2292
        gnutls.openpgp_crt_verify_self(crt, 0,
 
2293
                                       ctypes.byref(crtverify))
2062
2294
        if crtverify.value != 0:
2063
 
            gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2064
 
            raise gnutls.errors.CertificateSecurityError(
2065
 
                "Verify failed")
 
2295
            gnutls.openpgp_crt_deinit(crt)
 
2296
            raise gnutls.CertificateSecurityError("Verify failed")
2066
2297
        # New buffer for the fingerprint
2067
2298
        buf = ctypes.create_string_buffer(20)
2068
2299
        buf_len = ctypes.c_size_t()
2069
2300
        # Get the fingerprint from the certificate into the buffer
2070
 
        gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint(
2071
 
            crt, ctypes.byref(buf), ctypes.byref(buf_len))
 
2301
        gnutls.openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
 
2302
                                           ctypes.byref(buf_len))
2072
2303
        # Deinit the certificate
2073
 
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
2304
        gnutls.openpgp_crt_deinit(crt)
2074
2305
        # Convert the buffer to a Python bytestring
2075
2306
        fpr = ctypes.string_at(buf, buf_len.value)
2076
2307
        # Convert the bytestring to hexadecimal notation
2702
2933
        
2703
2934
        # "Use a log level over 10 to enable all debugging options."
2704
2935
        # - GnuTLS manual
2705
 
        gnutls.library.functions.gnutls_global_set_log_level(11)
 
2936
        gnutls.global_set_log_level(11)
2706
2937
        
2707
 
        @gnutls.library.types.gnutls_log_func
 
2938
        @gnutls.log_func
2708
2939
        def debug_gnutls(level, string):
2709
2940
            logger.debug("GnuTLS: %s", string[:-1])
2710
2941
        
2711
 
        gnutls.library.functions.gnutls_global_set_log_function(
2712
 
            debug_gnutls)
 
2942
        gnutls.global_set_log_function(debug_gnutls)
2713
2943
        
2714
2944
        # Redirect stdin so all checkers get /dev/null
2715
2945
        null = os.open(os.devnull, os.O_NOCTTY | os.O_RDWR)