481
435
.format(self.name)))
484
# Pretend that we have a GnuTLS module
485
class GnuTLS(object):
486
"""This isn't so much a class as it is a module-like namespace.
487
It is instantiated once, and simulates having a GnuTLS module."""
489
_library = ctypes.cdll.LoadLibrary(
490
ctypes.util.find_library("gnutls"))
491
_need_version = b"3.3.0"
493
# Need to use class name "GnuTLS" here, since this method is
494
# called before the assignment to the "gnutls" global variable
496
if GnuTLS.check_version(self._need_version) is None:
497
raise GnuTLS.Error("Needs GnuTLS {} or later"
498
.format(self._need_version))
500
# Unless otherwise indicated, the constants and types below are
501
# all from the gnutls/gnutls.h C header file.
511
E_NO_CERTIFICATE_FOUND = -49
512
OPENPGP_FMT_RAW = 0 # gnutls/openpgp.h
515
class session_int(ctypes.Structure):
517
session_t = ctypes.POINTER(session_int)
518
class certificate_credentials_st(ctypes.Structure):
520
certificate_credentials_t = ctypes.POINTER(
521
certificate_credentials_st)
522
certificate_type_t = ctypes.c_int
523
class datum_t(ctypes.Structure):
524
_fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
525
('size', ctypes.c_uint)]
526
class openpgp_crt_int(ctypes.Structure):
528
openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
529
openpgp_crt_fmt_t = ctypes.c_int # gnutls/openpgp.h
530
log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
531
credentials_type_t = ctypes.c_int
532
transport_ptr_t = ctypes.c_void_p
533
close_request_t = ctypes.c_int
536
class Error(Exception):
537
# We need to use the class name "GnuTLS" here, since this
538
# exception might be raised from within GnuTLS.__init__,
539
# which is called before the assignment to the "gnutls"
540
# global variable has happened.
541
def __init__(self, message = None, code = None, args=()):
542
# Default usage is by a message string, but if a return
543
# code is passed, convert it to a string with
546
if message is None and code is not None:
547
message = GnuTLS.strerror(code)
548
return super(GnuTLS.Error, self).__init__(
551
class CertificateSecurityError(Error):
555
class Credentials(object):
557
self._c_object = gnutls.certificate_credentials_t()
558
gnutls.certificate_allocate_credentials(
559
ctypes.byref(self._c_object))
560
self.type = gnutls.CRD_CERTIFICATE
563
gnutls.certificate_free_credentials(self._c_object)
565
class ClientSession(object):
566
def __init__(self, socket, credentials = None):
567
self._c_object = gnutls.session_t()
568
gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
569
gnutls.set_default_priority(self._c_object)
570
gnutls.transport_set_ptr(self._c_object, socket.fileno())
571
gnutls.handshake_set_private_extensions(self._c_object,
574
if credentials is None:
575
credentials = gnutls.Credentials()
576
gnutls.credentials_set(self._c_object, credentials.type,
577
ctypes.cast(credentials._c_object,
579
self.credentials = credentials
582
gnutls.deinit(self._c_object)
585
return gnutls.handshake(self._c_object)
587
def send(self, data):
591
data_len -= gnutls.record_send(self._c_object,
596
return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
598
# Error handling functions
599
def _error_code(result):
600
"""A function to raise exceptions on errors, suitable
601
for the 'restype' attribute on ctypes functions"""
604
if result == gnutls.E_NO_CERTIFICATE_FOUND:
605
raise gnutls.CertificateSecurityError(code = result)
606
raise gnutls.Error(code = result)
608
def _retry_on_error(result, func, arguments):
609
"""A function to retry on some errors, suitable
610
for the 'errcheck' attribute on ctypes functions"""
612
if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
613
return _error_code(result)
614
result = func(*arguments)
617
# Unless otherwise indicated, the function declarations below are
618
# all from the gnutls/gnutls.h C header file.
621
priority_set_direct = _library.gnutls_priority_set_direct
622
priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
623
ctypes.POINTER(ctypes.c_char_p)]
624
priority_set_direct.restype = _error_code
626
init = _library.gnutls_init
627
init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
628
init.restype = _error_code
630
set_default_priority = _library.gnutls_set_default_priority
631
set_default_priority.argtypes = [session_t]
632
set_default_priority.restype = _error_code
634
record_send = _library.gnutls_record_send
635
record_send.argtypes = [session_t, ctypes.c_void_p,
637
record_send.restype = ctypes.c_ssize_t
638
record_send.errcheck = _retry_on_error
640
certificate_allocate_credentials = (
641
_library.gnutls_certificate_allocate_credentials)
642
certificate_allocate_credentials.argtypes = [
643
ctypes.POINTER(certificate_credentials_t)]
644
certificate_allocate_credentials.restype = _error_code
646
certificate_free_credentials = (
647
_library.gnutls_certificate_free_credentials)
648
certificate_free_credentials.argtypes = [certificate_credentials_t]
649
certificate_free_credentials.restype = None
651
handshake_set_private_extensions = (
652
_library.gnutls_handshake_set_private_extensions)
653
handshake_set_private_extensions.argtypes = [session_t,
655
handshake_set_private_extensions.restype = None
657
credentials_set = _library.gnutls_credentials_set
658
credentials_set.argtypes = [session_t, credentials_type_t,
660
credentials_set.restype = _error_code
662
strerror = _library.gnutls_strerror
663
strerror.argtypes = [ctypes.c_int]
664
strerror.restype = ctypes.c_char_p
666
certificate_type_get = _library.gnutls_certificate_type_get
667
certificate_type_get.argtypes = [session_t]
668
certificate_type_get.restype = _error_code
670
certificate_get_peers = _library.gnutls_certificate_get_peers
671
certificate_get_peers.argtypes = [session_t,
672
ctypes.POINTER(ctypes.c_uint)]
673
certificate_get_peers.restype = ctypes.POINTER(datum_t)
675
global_set_log_level = _library.gnutls_global_set_log_level
676
global_set_log_level.argtypes = [ctypes.c_int]
677
global_set_log_level.restype = None
679
global_set_log_function = _library.gnutls_global_set_log_function
680
global_set_log_function.argtypes = [log_func]
681
global_set_log_function.restype = None
683
deinit = _library.gnutls_deinit
684
deinit.argtypes = [session_t]
685
deinit.restype = None
687
handshake = _library.gnutls_handshake
688
handshake.argtypes = [session_t]
689
handshake.restype = _error_code
690
handshake.errcheck = _retry_on_error
692
transport_set_ptr = _library.gnutls_transport_set_ptr
693
transport_set_ptr.argtypes = [session_t, transport_ptr_t]
694
transport_set_ptr.restype = None
696
bye = _library.gnutls_bye
697
bye.argtypes = [session_t, close_request_t]
698
bye.restype = _error_code
699
bye.errcheck = _retry_on_error
701
check_version = _library.gnutls_check_version
702
check_version.argtypes = [ctypes.c_char_p]
703
check_version.restype = ctypes.c_char_p
705
# All the function declarations below are from gnutls/openpgp.h
707
openpgp_crt_init = _library.gnutls_openpgp_crt_init
708
openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
709
openpgp_crt_init.restype = _error_code
711
openpgp_crt_import = _library.gnutls_openpgp_crt_import
712
openpgp_crt_import.argtypes = [openpgp_crt_t,
713
ctypes.POINTER(datum_t),
715
openpgp_crt_import.restype = _error_code
717
openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
718
openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
719
ctypes.POINTER(ctypes.c_uint)]
720
openpgp_crt_verify_self.restype = _error_code
722
openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
723
openpgp_crt_deinit.argtypes = [openpgp_crt_t]
724
openpgp_crt_deinit.restype = None
726
openpgp_crt_get_fingerprint = (
727
_library.gnutls_openpgp_crt_get_fingerprint)
728
openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
732
openpgp_crt_get_fingerprint.restype = _error_code
734
# Remove non-public functions
735
del _error_code, _retry_on_error
736
# Create the global "gnutls" object, simulating a module
739
438
def call_pipe(connection, # : multiprocessing.Connection
740
439
func, *args, **kwargs):
741
440
"""This function is meant to be called by multiprocessing.Process
2312
2044
def fingerprint(openpgp):
2313
2045
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
2314
2046
# New GnuTLS "datum" with the OpenPGP public key
2315
datum = gnutls.datum_t(
2047
datum = gnutls.library.types.gnutls_datum_t(
2316
2048
ctypes.cast(ctypes.c_char_p(openpgp),
2317
2049
ctypes.POINTER(ctypes.c_ubyte)),
2318
2050
ctypes.c_uint(len(openpgp)))
2319
2051
# New empty GnuTLS certificate
2320
crt = gnutls.openpgp_crt_t()
2321
gnutls.openpgp_crt_init(ctypes.byref(crt))
2052
crt = gnutls.library.types.gnutls_openpgp_crt_t()
2053
gnutls.library.functions.gnutls_openpgp_crt_init(
2322
2055
# Import the OpenPGP public key into the certificate
2323
gnutls.openpgp_crt_import(crt, ctypes.byref(datum),
2324
gnutls.OPENPGP_FMT_RAW)
2056
gnutls.library.functions.gnutls_openpgp_crt_import(
2057
crt, ctypes.byref(datum),
2058
gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
2325
2059
# Verify the self signature in the key
2326
2060
crtverify = ctypes.c_uint()
2327
gnutls.openpgp_crt_verify_self(crt, 0,
2328
ctypes.byref(crtverify))
2061
gnutls.library.functions.gnutls_openpgp_crt_verify_self(
2062
crt, 0, ctypes.byref(crtverify))
2329
2063
if crtverify.value != 0:
2330
gnutls.openpgp_crt_deinit(crt)
2331
raise gnutls.CertificateSecurityError("Verify failed")
2064
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2065
raise gnutls.errors.CertificateSecurityError(
2332
2067
# New buffer for the fingerprint
2333
2068
buf = ctypes.create_string_buffer(20)
2334
2069
buf_len = ctypes.c_size_t()
2335
2070
# Get the fingerprint from the certificate into the buffer
2336
gnutls.openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
2337
ctypes.byref(buf_len))
2071
gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint(
2072
crt, ctypes.byref(buf), ctypes.byref(buf_len))
2338
2073
# Deinit the certificate
2339
gnutls.openpgp_crt_deinit(crt)
2074
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2340
2075
# Convert the buffer to a Python bytestring
2341
2076
fpr = ctypes.string_at(buf, buf_len.value)
2342
2077
# Convert the bytestring to hexadecimal notation