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