@@ -16,39 +16,120 @@ from enum import IntEnum
16
16
from gssapi.raw._enum_extensions import ExtendableEnum
17
17
18
18
19
- cdef extern from " python_gssapi_ext.h" :
20
- # NB(directxman12): this wiki page has a different argument order
21
- # than the header file, and uses size_t instead of int
22
- # (this file matches the header file)
23
- OM_uint32 gss_wrap_iov(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
24
- int conf_req_flag, gss_qop_t qop_req, int * conf_ret,
25
- gss_iov_buffer_desc * iov, int iov_count) nogil
26
-
27
- OM_uint32 gss_unwrap_iov(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
28
- int * conf_ret, gss_qop_t * qop_ret,
29
- gss_iov_buffer_desc * iov, int iov_count) nogil
30
-
31
- OM_uint32 gss_wrap_iov_length(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
32
- int conf_req, gss_qop_t qop_req,
33
- int * conf_ret, gss_iov_buffer_desc * iov,
34
- int iov_count) nogil
35
-
36
- OM_uint32 gss_release_iov_buffer(OM_uint32 * min_stat,
37
- gss_iov_buffer_desc * iov,
38
- int iov_count) nogil
39
-
40
- OM_uint32 gss_wrap_aead(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
41
- int conf_req, gss_qop_t qop_req,
42
- gss_buffer_t input_assoc_buffer,
43
- gss_buffer_t input_payload_buffer, int * conf_ret,
44
- gss_buffer_t output_message_buffer) nogil
45
-
46
- OM_uint32 gss_unwrap_aead(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
47
- gss_buffer_t input_message_buffer,
48
- gss_buffer_t input_assoc_buffer,
49
- gss_buffer_t output_payload_buffer,
50
- int * conf_ret, gss_qop_t * qop_ret) nogil
19
+ IF MACOS_FRAMEWORK_PATH:
20
+ # GSS.Framework (macOS) does not expose the 4 gss IOV functions in its
21
+ # header. Instead dynamically lookup the function address in the GSS
22
+ # library file based on the known symbol name.
23
+
24
+ from posix.dlfcn cimport dlopen, dlerror, dlsym, dlclose, RTLD_NOW, \
25
+ RTLD_GLOBAL
26
+
27
+ cdef:
28
+ void * gss = NULL
29
+ void * wrap_iov_fn = NULL
30
+ void * unwrap_iov_fn = NULL
31
+ void * wrap_iov_length_fn = NULL
32
+ void * release_iov_buffer_fn = NULL
33
+
34
+ cdef void * _dlsym(void * handle, name):
35
+ # dlsym() returns NULL for a symbol that is not found but it could
36
+ # also return NULL as a valid symbol address. The correct way to test
37
+ # on an error is to:
38
+ # 1. call dlerror() to clear any existing errors,
39
+ # 2. call dlsym, then
40
+ # 3. call dlerror() to check whether that is NULL or not
41
+ # https://man7.org/linux/man-pages/man3/dlsym.3.html
42
+ dlerror()
43
+
44
+ hn = dlsym(handle, name)
45
+ err_msg = dlerror()
46
+ if err_msg != NULL :
47
+ raise ImportError (err_msg.decode(' utf-8' , errors = ' replace' ))
48
+
49
+ return hn
50
+
51
+ gss = dlopen(MACOS_FRAMEWORK_PATH.encode(), RTLD_NOW | RTLD_GLOBAL)
52
+ if gss == NULL :
53
+ raise ImportError (dlerror().decode(' utf-8' , errors = ' replace' ))
54
+
55
+ try :
56
+ # The symbol names were found when inspecting the GSS library file
57
+ # 'nm -gU /path/GSS'. Can confirm these symbols are present in the
58
+ # latest (10.15) to at least 10.11. Online docs seem to confirm these
59
+ # symbols have been present since iOS 6.0 which is roughly when this
60
+ # framework was introduced.
61
+ wrap_iov_fn = _dlsym(gss, b' __ApplePrivate_gss_wrap_iov' )
62
+ unwrap_iov_fn = _dlsym(gss, b' __ApplePrivate_gss_unwrap_iov' )
63
+ wrap_iov_length_fn = _dlsym(gss, b' __ApplePrivate_gss_wrap_iov_length' )
64
+ release_iov_buffer_fn = _dlsym(
65
+ gss, b' __ApplePrivate_gss_release_iov_buffer' )
66
+
67
+ finally :
68
+ dlclose(gss)
69
+
70
+ cdef OM_uint32 gss_wrap_iov(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
71
+ int conf_req_flag, gss_qop_t qop_req,
72
+ int * conf_ret, gss_iov_buffer_desc * iov,
73
+ int iov_count) nogil:
74
+
75
+ return (< OM_uint32(* )(OM_uint32* , gss_ctx_id_t, int , gss_qop_t, int * ,
76
+ gss_iov_buffer_desc* , int ) nogil> wrap_iov_fn)(
77
+ min_stat, ctx_handle, conf_req_flag, qop_req, conf_ret, iov,
78
+ iov_count)
79
+
80
+ cdef OM_uint32 gss_unwrap_iov(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
81
+ int * conf_ret, gss_qop_t * qop_ret,
82
+ gss_iov_buffer_desc * iov,
83
+ int iov_count) nogil:
84
+
85
+ return (< OM_uint32(* )(OM_uint32* , gss_ctx_id_t, int * , gss_qop_t* ,
86
+ gss_iov_buffer_desc* , int ) nogil> unwrap_iov_fn)(
87
+ min_stat, ctx_handle, conf_ret, qop_ret, iov, iov_count)
88
+
89
+ cdef OM_uint32 gss_wrap_iov_length(OM_uint32 * min_stat,
90
+ gss_ctx_id_t ctx_handle, int conf_req,
91
+ gss_qop_t qop_req, int * conf_ret,
92
+ gss_iov_buffer_desc * iov,
93
+ int iov_count) nogil:
94
+
95
+ return (< OM_uint32(* )(OM_uint32* , gss_ctx_id_t, int , gss_qop_t, int * ,
96
+ gss_iov_buffer_desc* , int ) nogil> wrap_iov_length_fn)(
97
+ min_stat, ctx_handle, conf_req, qop_req, conf_ret, iov, iov_count)
98
+
99
+ cdef OM_uint32 gss_release_iov_buffer(OM_uint32 * min_stat,
100
+ gss_iov_buffer_desc * iov,
101
+ int iov_count) nogil:
102
+
103
+ return (< OM_uint32(* )(OM_uint32* , gss_iov_buffer_desc* ,
104
+ int ) nogil> release_iov_buffer_fn)(
105
+ min_stat, iov, iov_count)
106
+
107
+ ELSE :
108
+ cdef extern from " python_gssapi_ext.h" :
109
+ # NB(directxman12): this wiki page has a different argument order
110
+ # than the header file, and uses size_t instead of
111
+ # int (this file matches the header file)
112
+ OM_uint32 gss_wrap_iov(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
113
+ int conf_req_flag, gss_qop_t qop_req,
114
+ int * conf_ret, gss_iov_buffer_desc * iov,
115
+ int iov_count) nogil
116
+
117
+ OM_uint32 gss_unwrap_iov(OM_uint32 * min_stat, gss_ctx_id_t ctx_handle,
118
+ int * conf_ret, gss_qop_t * qop_ret,
119
+ gss_iov_buffer_desc * iov, int iov_count) nogil
120
+
121
+ OM_uint32 gss_wrap_iov_length(OM_uint32 * min_stat,
122
+ gss_ctx_id_t ctx_handle, int conf_req,
123
+ gss_qop_t qop_req, int * conf_ret,
124
+ gss_iov_buffer_desc * iov,
125
+ int iov_count) nogil
126
+
127
+ OM_uint32 gss_release_iov_buffer(OM_uint32 * min_stat,
128
+ gss_iov_buffer_desc * iov,
129
+ int iov_count) nogil
130
+
51
131
132
+ cdef extern from " python_gssapi_ext.h" :
52
133
gss_iov_buffer_t GSS_C_NO_IOV_BUFFER
53
134
54
135
OM_uint32 GSS_IOV_BUFFER_TYPE_EMPTY
@@ -447,109 +528,3 @@ def wrap_iov_length(SecurityContext context not None, IOV message not None,
447
528
return < bint> conf_used
448
529
else :
449
530
raise GSSError(maj_stat, min_stat)
450
-
451
-
452
- def wrap_aead (SecurityContext context not None , bytes message not None ,
453
- bytes associated = None , confidential = True , qop = None ):
454
- """
455
- wrap_aead(context, message, associated=None, confidential=True, qop=None)
456
- Wrap/Encrypt an AEAD message.
457
-
458
- This method takes an input message and associated data,
459
- and outputs and AEAD message.
460
-
461
- Args:
462
- context (SecurityContext): the current security context
463
- message (bytes): the message to wrap or encrypt
464
- associated (bytes): associated data to go with the message
465
- confidential (bool): whether or not to encrypt the message (True),
466
- or just wrap it with a MIC (False)
467
- qop (int): the desired Quality of Protection
468
- (or None for the default QoP)
469
-
470
- Returns:
471
- WrapResult: the wrapped/encrypted total message, and whether or not
472
- encryption was actually used
473
-
474
- Raises:
475
- GSSError
476
- """
477
-
478
- cdef int conf_req = confidential
479
- cdef gss_qop_t qop_req = qop if qop is not None else GSS_C_QOP_DEFAULT
480
- cdef gss_buffer_desc message_buffer = gss_buffer_desc(len (message),
481
- message)
482
-
483
- cdef gss_buffer_t assoc_buffer_ptr = GSS_C_NO_BUFFER
484
- cdef gss_buffer_desc assoc_buffer
485
- if associated is not None :
486
- assoc_buffer = gss_buffer_desc(len (associated), associated)
487
- assoc_buffer_ptr = & assoc_buffer
488
-
489
- cdef int conf_used
490
- # GSS_C_EMPTY_BUFFER
491
- cdef gss_buffer_desc output_buffer = gss_buffer_desc(0 , NULL )
492
-
493
- cdef OM_uint32 maj_stat, min_stat
494
-
495
- with nogil:
496
- maj_stat = gss_wrap_aead(& min_stat, context.raw_ctx, conf_req, qop_req,
497
- assoc_buffer_ptr, & message_buffer,
498
- & conf_used, & output_buffer)
499
-
500
- if maj_stat == GSS_S_COMPLETE:
501
- output_message = (< char * > output_buffer.value)[:output_buffer.length]
502
- gss_release_buffer(& min_stat, & output_buffer)
503
- return WrapResult(output_message, < bint> conf_used)
504
- else :
505
- raise GSSError(maj_stat, min_stat)
506
-
507
-
508
- def unwrap_aead (SecurityContext context not None , bytes message not None ,
509
- bytes associated = None ):
510
- """
511
- unwrap_aead(context, message, associated=None)
512
- Unwrap/Decrypt an AEAD message.
513
-
514
- This method takes an encrpyted/wrapped AEAD message and some associated
515
- data, and returns an unwrapped/decrypted message.
516
-
517
- Args:
518
- context (SecurityContext): the current security context
519
- message (bytes): the AEAD message to unwrap or decrypt
520
- associated (bytes): associated data that goes with the message
521
-
522
- Returns:
523
- UnwrapResult: the unwrapped/decrypted message, whether or on
524
- encryption was used, and the QoP used
525
-
526
- Raises:
527
- GSSError
528
- """
529
-
530
- cdef gss_buffer_desc input_buffer = gss_buffer_desc(len (message), message)
531
-
532
- cdef gss_buffer_t assoc_buffer_ptr = GSS_C_NO_BUFFER
533
- cdef gss_buffer_desc assoc_buffer
534
- if associated is not None :
535
- assoc_buffer = gss_buffer_desc(len (associated), associated)
536
- assoc_buffer_ptr = & assoc_buffer
537
-
538
- # GSS_C_EMPTY_BUFFER
539
- cdef gss_buffer_desc output_buffer = gss_buffer_desc(0 , NULL )
540
- cdef int conf_state
541
- cdef gss_qop_t qop_state
542
-
543
- cdef OM_uint32 maj_stat, min_stat
544
-
545
- with nogil:
546
- maj_stat = gss_unwrap_aead(& min_stat, context.raw_ctx, & input_buffer,
547
- assoc_buffer_ptr, & output_buffer,
548
- & conf_state, & qop_state)
549
-
550
- if maj_stat == GSS_S_COMPLETE:
551
- output_message = (< char * > output_buffer.value)[:output_buffer.length]
552
- gss_release_buffer(& min_stat, & output_buffer)
553
- return UnwrapResult(output_message, < bint> conf_state, qop_state)
554
- else :
555
- raise GSSError(maj_stat, min_stat)
0 commit comments