434
429
.format(self.name)))
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."""
437
_library = ctypes.cdll.LoadLibrary(
438
ctypes.util.find_library("gnutls"))
439
_need_version = "3.3.0"
441
# Need to use class name "GnuTLS" here, since this method is
442
# called before the assignment to the "gnutls" global variable
444
if GnuTLS.check_version(self._need_version) is None:
445
raise GnuTLS.Error("Needs GnuTLS {} or later"
446
.format(self._need_version))
448
# Unless otherwise indicated, the constants and types below are
449
# all from the gnutls/gnutls.h C header file.
457
E_NO_CERTIFICATE_FOUND = -49
458
OPENPGP_FMT_RAW = 0 # gnutls/openpgp.h
461
class session_int(ctypes.Structure):
463
session_t = ctypes.POINTER(session_int)
464
class certificate_credentials_st(ctypes.Structure):
466
certificate_credentials_t = ctypes.POINTER(
467
certificate_credentials_st)
468
certificate_type_t = ctypes.c_int
469
class datum_t(ctypes.Structure):
470
_fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
471
('size', ctypes.c_uint)]
472
class openpgp_crt_int(ctypes.Structure):
474
openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
475
openpgp_crt_fmt_t = ctypes.c_int # gnutls/openpgp.h
476
log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
477
credentials_type_t = ctypes.c_int #
478
transport_ptr_t = ctypes.c_void_p
479
close_request_t = ctypes.c_int
482
class Error(Exception):
483
# We need to use the class name "GnuTLS" here, since this
484
# exception might be raised from within GnuTLS.__init__,
485
# which is called before the assignment to the "gnutls"
486
# global variable happens.
487
def __init__(self, message = None, code = None, args=()):
488
# Default usage is by a message string, but if a return
489
# code is passed, convert it to a string with
491
if message is None and code is not None:
492
message = GnuTLS.strerror(code)
493
return super(GnuTLS.Error, self).__init__(
496
class CertificateSecurityError(Error):
500
class Credentials(object):
502
self._c_object = gnutls.certificate_credentials_t()
503
gnutls.certificate_allocate_credentials(
504
ctypes.byref(self._c_object))
505
self.type = gnutls.CRD_CERTIFICATE
508
gnutls.certificate_free_credentials(self._c_object)
510
class ClientSession(object):
511
def __init__(self, socket, credentials = None):
512
self._c_object = gnutls.session_t()
513
gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
514
gnutls.set_default_priority(self._c_object)
515
gnutls.transport_set_ptr(self._c_object, socket.fileno())
516
gnutls.handshake_set_private_extensions(self._c_object,
519
if credentials is None:
520
credentials = gnutls.Credentials()
521
gnutls.credentials_set(self._c_object, credentials.type,
522
ctypes.cast(credentials._c_object,
524
self.credentials = credentials
527
gnutls.deinit(self._c_object)
530
return gnutls.handshake(self._c_object)
532
def send(self, data):
536
return gnutls.record_send(self._c_object, data, len(data))
539
return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
541
# Error handling function
542
def _error_code(result):
543
"""A function to raise exceptions on errors, suitable
544
for the 'restype' attribute on ctypes functions"""
547
if result == gnutls.E_NO_CERTIFICATE_FOUND:
548
raise gnutls.CertificateSecurityError(code = result)
549
raise gnutls.Error(code = result)
551
# Unless otherwise indicated, the function declarations below are
552
# all from the gnutls/gnutls.h C header file.
555
priority_set_direct = _library.gnutls_priority_set_direct
556
priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
557
ctypes.POINTER(ctypes.c_char_p)]
558
priority_set_direct.restype = _error_code
560
init = _library.gnutls_init
561
init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
562
init.restype = _error_code
564
set_default_priority = _library.gnutls_set_default_priority
565
set_default_priority.argtypes = [session_t]
566
set_default_priority.restype = _error_code
568
record_send = _library.gnutls_record_send
569
record_send.argtypes = [session_t, ctypes.c_void_p,
571
record_send.restype = ctypes.c_ssize_t
573
certificate_allocate_credentials = (
574
_library.gnutls_certificate_allocate_credentials)
575
certificate_allocate_credentials.argtypes = [
576
ctypes.POINTER(certificate_credentials_t)]
577
certificate_allocate_credentials.restype = _error_code
579
certificate_free_credentials = (
580
_library.gnutls_certificate_free_credentials)
581
certificate_free_credentials.argtypes = [certificate_credentials_t]
582
certificate_free_credentials.restype = None
584
handshake_set_private_extensions = (
585
_library.gnutls_handshake_set_private_extensions)
586
handshake_set_private_extensions.argtypes = [session_t,
588
handshake_set_private_extensions.restype = None
590
credentials_set = _library.gnutls_credentials_set
591
credentials_set.argtypes = [session_t, credentials_type_t,
593
credentials_set.restype = _error_code
595
strerror = _library.gnutls_strerror
596
strerror.argtypes = [ctypes.c_int]
597
strerror.restype = ctypes.c_char_p
599
certificate_type_get = _library.gnutls_certificate_type_get
600
certificate_type_get.argtypes = [session_t]
601
certificate_type_get.restype = _error_code
603
certificate_get_peers = _library.gnutls_certificate_get_peers
604
certificate_get_peers.argtypes = [session_t,
605
ctypes.POINTER(ctypes.c_uint)]
606
certificate_get_peers.restype = ctypes.POINTER(datum_t)
608
global_set_log_level = _library.gnutls_global_set_log_level
609
global_set_log_level.argtypes = [ctypes.c_int]
610
global_set_log_level.restype = None
612
global_set_log_function = _library.gnutls_global_set_log_function
613
global_set_log_function.argtypes = [log_func]
614
global_set_log_function.restype = None
616
deinit = _library.gnutls_deinit
617
deinit.argtypes = [session_t]
618
deinit.restype = None
620
handshake = _library.gnutls_handshake
621
handshake.argtypes = [session_t]
622
handshake.restype = _error_code
624
transport_set_ptr = _library.gnutls_transport_set_ptr
625
transport_set_ptr.argtypes = [session_t, transport_ptr_t]
626
transport_set_ptr.restype = None
628
bye = _library.gnutls_bye
629
bye.argtypes = [session_t, close_request_t]
630
bye.restype = _error_code
632
check_version = _library.gnutls_check_version
633
check_version.argtypes = [ctypes.c_char_p]
634
check_version.restype = ctypes.c_char_p
636
# All the function declarations below are from gnutls/openpgp.h
638
openpgp_crt_init = _library.gnutls_openpgp_crt_init
639
openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
640
openpgp_crt_init.restype = _error_code
642
openpgp_crt_import = _library.gnutls_openpgp_crt_import
643
openpgp_crt_import.argtypes = [openpgp_crt_t,
644
ctypes.POINTER(datum_t),
646
openpgp_crt_import.restype = _error_code
648
openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
649
openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
650
ctypes.POINTER(ctypes.c_uint)]
651
openpgp_crt_verify_self.restype = _error_code
653
openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
654
openpgp_crt_deinit.argtypes = [openpgp_crt_t]
655
openpgp_crt_deinit.restype = None
657
openpgp_crt_get_fingerprint = (
658
_library.gnutls_openpgp_crt_get_fingerprint)
659
openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
663
openpgp_crt_get_fingerprint.restype = _error_code
665
# Remove non-public function
667
# Create the global "gnutls" object, simulating a module
437
670
def call_pipe(connection, # : multiprocessing.Connection
438
671
func, *args, **kwargs):
439
672
"""This function is meant to be called by multiprocessing.Process
2043
2266
def fingerprint(openpgp):
2044
2267
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
2045
2268
# New GnuTLS "datum" with the OpenPGP public key
2046
datum = gnutls.library.types.gnutls_datum_t(
2269
datum = gnutls.datum_t(
2047
2270
ctypes.cast(ctypes.c_char_p(openpgp),
2048
2271
ctypes.POINTER(ctypes.c_ubyte)),
2049
2272
ctypes.c_uint(len(openpgp)))
2050
2273
# New empty GnuTLS certificate
2051
crt = gnutls.library.types.gnutls_openpgp_crt_t()
2052
gnutls.library.functions.gnutls_openpgp_crt_init(
2274
crt = gnutls.openpgp_crt_t()
2275
gnutls.openpgp_crt_init(ctypes.byref(crt))
2054
2276
# 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)
2277
gnutls.openpgp_crt_import(crt, ctypes.byref(datum),
2278
gnutls.OPENPGP_FMT_RAW)
2058
2279
# Verify the self signature in the key
2059
2280
crtverify = ctypes.c_uint()
2060
gnutls.library.functions.gnutls_openpgp_crt_verify_self(
2061
crt, 0, ctypes.byref(crtverify))
2281
gnutls.openpgp_crt_verify_self(crt, 0,
2282
ctypes.byref(crtverify))
2062
2283
if crtverify.value != 0:
2063
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2064
raise gnutls.errors.CertificateSecurityError(
2284
gnutls.openpgp_crt_deinit(crt)
2285
raise gnutls.CertificateSecurityError("Verify failed")
2066
2286
# New buffer for the fingerprint
2067
2287
buf = ctypes.create_string_buffer(20)
2068
2288
buf_len = ctypes.c_size_t()
2069
2289
# 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))
2290
gnutls.openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
2291
ctypes.byref(buf_len))
2072
2292
# Deinit the certificate
2073
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2293
gnutls.openpgp_crt_deinit(crt)
2074
2294
# Convert the buffer to a Python bytestring
2075
2295
fpr = ctypes.string_at(buf, buf_len.value)
2076
2296
# Convert the bytestring to hexadecimal notation