Skip to content

Commit

Permalink
Support DCE IOV functions on macOS
Browse files Browse the repository at this point in the history
The DCE IOV functions on macOS are not exported by any public header on
the GSS.Framework.  While the symbols are considered to be private they
haven't changed across any macOS version since the introduction of
GSS.Framework.  Since the inclusion of ext_dce is still dependent on
whether the symbol is present at compile time, their usage in
python-gssapi is relatively safe.  Provide our own copy of the
definitions accordingly.

The `-framework GSS.framework` has also been removed from the compiler
args as clang emits a warning with these present, and it is only needed
for linking.

Signed-off-by: Jordan Borean <jborean93@gmail.com>
[rharwood@redhat.com: C style, slight comment/commit message tweaks]
  • Loading branch information
jborean93 authored and frozencemetery committed Aug 6, 2021
1 parent 69f8b3a commit 2bccab4
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 128 deletions.
4 changes: 4 additions & 0 deletions docs/source/gssapi.raw.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ DCE (IOV/AEAD) Extensions
:members:
:undoc-members:

.. automodule:: gssapi.raw.ext_dce_aead
:members:
:undoc-members:

IOV MIC Extensions
~~~~~~~~~~~~~~~~~~

Expand Down
8 changes: 7 additions & 1 deletion gssapi/raw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,20 @@
except ImportError:
pass

# optional DCE (IOV/AEAD) support
# optional DCE (IOV) support
try:
from gssapi.raw.ext_dce import * # noqa
# optional IOV MIC support (requires DCE support)
from gssapi.raw.ext_iov_mic import * # noqa
except ImportError:
pass

# optional DCE (AEAD) support
try:
from gssapi.raw.ext_dce_aead import * # noqa
except ImportError:
pass

# optional RFC 6680 support
try:
from gssapi.raw.ext_rfc6680 import * # noqa
Expand Down
135 changes: 16 additions & 119 deletions gssapi/raw/ext_dce.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,30 @@ from gssapi.raw.sec_contexts cimport SecurityContext

from gssapi.raw.misc import GSSError
from gssapi.raw import types as gssapi_types
from gssapi.raw.named_tuples import IOVUnwrapResult, WrapResult, UnwrapResult
from gssapi.raw.named_tuples import IOVUnwrapResult
from collections import namedtuple
from collections.abc import Sequence

from enum import IntEnum
from gssapi.raw._enum_extensions import ExtendableEnum

# Kept for backwards compatibility - functions used to be declared here
try:
from gssapi.raw.ext_dce_aead import wrap_aead, unwrap_aead
except ImportError:
pass


cdef extern from "python_gssapi_ext.h":
"""
#ifdef OSX_HAS_GSS_FRAMEWORK
#define gss_wrap_iov __ApplePrivate_gss_wrap_iov
#define gss_unwrap_iov __ApplePrivate_gss_unwrap_iov
#define gss_wrap_iov_length __ApplePrivate_gss_wrap_iov_length
#define gss_release_iov_buffer __ApplePrivate_gss_release_iov_buffer
#endif
"""

# NB(directxman12): this wiki page has a different argument order
# than the header file, and uses size_t instead of int
# (this file matches the header file)
Expand All @@ -37,18 +52,6 @@ cdef extern from "python_gssapi_ext.h":
gss_iov_buffer_desc *iov,
int iov_count) nogil

OM_uint32 gss_wrap_aead(OM_uint32 *min_stat, gss_ctx_id_t ctx_handle,
int conf_req, gss_qop_t qop_req,
gss_buffer_t input_assoc_buffer,
gss_buffer_t input_payload_buffer, int *conf_ret,
gss_buffer_t output_message_buffer) nogil

OM_uint32 gss_unwrap_aead(OM_uint32 *min_stat, gss_ctx_id_t ctx_handle,
gss_buffer_t input_message_buffer,
gss_buffer_t input_assoc_buffer,
gss_buffer_t output_payload_buffer,
int *conf_ret, gss_qop_t *qop_ret) nogil

gss_iov_buffer_t GSS_C_NO_IOV_BUFFER

OM_uint32 GSS_IOV_BUFFER_TYPE_EMPTY
Expand Down Expand Up @@ -447,109 +450,3 @@ def wrap_iov_length(SecurityContext context not None, IOV message not None,
return <bint>conf_used
else:
raise GSSError(maj_stat, min_stat)


def wrap_aead(SecurityContext context not None, bytes message not None,
bytes associated=None, confidential=True, qop=None):
"""
wrap_aead(context, message, associated=None, confidential=True, qop=None)
Wrap/Encrypt an AEAD message.
This method takes an input message and associated data,
and outputs and AEAD message.
Args:
context (SecurityContext): the current security context
message (bytes): the message to wrap or encrypt
associated (bytes): associated data to go with the message
confidential (bool): whether or not to encrypt the message (True),
or just wrap it with a MIC (False)
qop (int): the desired Quality of Protection
(or None for the default QoP)
Returns:
WrapResult: the wrapped/encrypted total message, and whether or not
encryption was actually used
Raises:
GSSError
"""

cdef int conf_req = confidential
cdef gss_qop_t qop_req = qop if qop is not None else GSS_C_QOP_DEFAULT
cdef gss_buffer_desc message_buffer = gss_buffer_desc(len(message),
message)

cdef gss_buffer_t assoc_buffer_ptr = GSS_C_NO_BUFFER
cdef gss_buffer_desc assoc_buffer
if associated is not None:
assoc_buffer = gss_buffer_desc(len(associated), associated)
assoc_buffer_ptr = &assoc_buffer

cdef int conf_used
# GSS_C_EMPTY_BUFFER
cdef gss_buffer_desc output_buffer = gss_buffer_desc(0, NULL)

cdef OM_uint32 maj_stat, min_stat

with nogil:
maj_stat = gss_wrap_aead(&min_stat, context.raw_ctx, conf_req, qop_req,
assoc_buffer_ptr, &message_buffer,
&conf_used, &output_buffer)

if maj_stat == GSS_S_COMPLETE:
output_message = (<char*>output_buffer.value)[:output_buffer.length]
gss_release_buffer(&min_stat, &output_buffer)
return WrapResult(output_message, <bint>conf_used)
else:
raise GSSError(maj_stat, min_stat)


def unwrap_aead(SecurityContext context not None, bytes message not None,
bytes associated=None):
"""
unwrap_aead(context, message, associated=None)
Unwrap/Decrypt an AEAD message.
This method takes an encrpyted/wrapped AEAD message and some associated
data, and returns an unwrapped/decrypted message.
Args:
context (SecurityContext): the current security context
message (bytes): the AEAD message to unwrap or decrypt
associated (bytes): associated data that goes with the message
Returns:
UnwrapResult: the unwrapped/decrypted message, whether or on
encryption was used, and the QoP used
Raises:
GSSError
"""

cdef gss_buffer_desc input_buffer = gss_buffer_desc(len(message), message)

cdef gss_buffer_t assoc_buffer_ptr = GSS_C_NO_BUFFER
cdef gss_buffer_desc assoc_buffer
if associated is not None:
assoc_buffer = gss_buffer_desc(len(associated), associated)
assoc_buffer_ptr = &assoc_buffer

# GSS_C_EMPTY_BUFFER
cdef gss_buffer_desc output_buffer = gss_buffer_desc(0, NULL)
cdef int conf_state
cdef gss_qop_t qop_state

cdef OM_uint32 maj_stat, min_stat

with nogil:
maj_stat = gss_unwrap_aead(&min_stat, context.raw_ctx, &input_buffer,
assoc_buffer_ptr, &output_buffer,
&conf_state, &qop_state)

if maj_stat == GSS_S_COMPLETE:
output_message = (<char*>output_buffer.value)[:output_buffer.length]
gss_release_buffer(&min_stat, &output_buffer)
return UnwrapResult(output_message, <bint>conf_state, qop_state)
else:
raise GSSError(maj_stat, min_stat)
127 changes: 127 additions & 0 deletions gssapi/raw/ext_dce_aead.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
GSSAPI="BASE" # This ensures that a full module is generated by Cython

from gssapi.raw.cython_types cimport *
from gssapi.raw.sec_contexts cimport SecurityContext

from gssapi.raw.misc import GSSError
from gssapi.raw.named_tuples import WrapResult, UnwrapResult


cdef extern from "python_gssapi_ext.h":
OM_uint32 gss_wrap_aead(OM_uint32 *min_stat, gss_ctx_id_t ctx_handle,
int conf_req, gss_qop_t qop_req,
gss_buffer_t input_assoc_buffer,
gss_buffer_t input_payload_buffer, int *conf_ret,
gss_buffer_t output_message_buffer) nogil

OM_uint32 gss_unwrap_aead(OM_uint32 *min_stat, gss_ctx_id_t ctx_handle,
gss_buffer_t input_message_buffer,
gss_buffer_t input_assoc_buffer,
gss_buffer_t output_payload_buffer,
int *conf_ret, gss_qop_t *qop_ret) nogil


def wrap_aead(SecurityContext context not None, bytes message not None,
bytes associated=None, confidential=True, qop=None):
"""
wrap_aead(context, message, associated=None, confidential=True, qop=None)
Wrap/Encrypt an AEAD message.
This method takes an input message and associated data,
and outputs and AEAD message.
Args:
context (SecurityContext): the current security context
message (bytes): the message to wrap or encrypt
associated (bytes): associated data to go with the message
confidential (bool): whether or not to encrypt the message (True),
or just wrap it with a MIC (False)
qop (int): the desired Quality of Protection
(or None for the default QoP)
Returns:
WrapResult: the wrapped/encrypted total message, and whether or not
encryption was actually used
Raises:
GSSError
"""

cdef int conf_req = confidential
cdef gss_qop_t qop_req = qop if qop is not None else GSS_C_QOP_DEFAULT
cdef gss_buffer_desc message_buffer = gss_buffer_desc(len(message),
message)

cdef gss_buffer_t assoc_buffer_ptr = GSS_C_NO_BUFFER
cdef gss_buffer_desc assoc_buffer
if associated is not None:
assoc_buffer = gss_buffer_desc(len(associated), associated)
assoc_buffer_ptr = &assoc_buffer

cdef int conf_used
# GSS_C_EMPTY_BUFFER
cdef gss_buffer_desc output_buffer = gss_buffer_desc(0, NULL)

cdef OM_uint32 maj_stat, min_stat

with nogil:
maj_stat = gss_wrap_aead(&min_stat, context.raw_ctx, conf_req, qop_req,
assoc_buffer_ptr, &message_buffer,
&conf_used, &output_buffer)

if maj_stat == GSS_S_COMPLETE:
output_message = (<char*>output_buffer.value)[:output_buffer.length]
gss_release_buffer(&min_stat, &output_buffer)
return WrapResult(output_message, <bint>conf_used)
else:
raise GSSError(maj_stat, min_stat)


def unwrap_aead(SecurityContext context not None, bytes message not None,
bytes associated=None):
"""
unwrap_aead(context, message, associated=None)
Unwrap/Decrypt an AEAD message.
This method takes an encrpyted/wrapped AEAD message and some associated
data, and returns an unwrapped/decrypted message.
Args:
context (SecurityContext): the current security context
message (bytes): the AEAD message to unwrap or decrypt
associated (bytes): associated data that goes with the message
Returns:
UnwrapResult: the unwrapped/decrypted message, whether or on
encryption was used, and the QoP used
Raises:
GSSError
"""

cdef gss_buffer_desc input_buffer = gss_buffer_desc(len(message), message)

cdef gss_buffer_t assoc_buffer_ptr = GSS_C_NO_BUFFER
cdef gss_buffer_desc assoc_buffer
if associated is not None:
assoc_buffer = gss_buffer_desc(len(associated), associated)
assoc_buffer_ptr = &assoc_buffer

# GSS_C_EMPTY_BUFFER
cdef gss_buffer_desc output_buffer = gss_buffer_desc(0, NULL)
cdef int conf_state
cdef gss_qop_t qop_state

cdef OM_uint32 maj_stat, min_stat

with nogil:
maj_stat = gss_unwrap_aead(&min_stat, context.raw_ctx, &input_buffer,
assoc_buffer_ptr, &output_buffer,
&conf_state, &qop_state)

if maj_stat == GSS_S_COMPLETE:
output_message = (<char*>output_buffer.value)[:output_buffer.length]
gss_release_buffer(&min_stat, &output_buffer)
return UnwrapResult(output_message, <bint>conf_state, qop_state)
else:
raise GSSError(maj_stat, min_stat)
39 changes: 37 additions & 2 deletions gssapi/raw/python_gssapi_ext.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
#ifdef OSX_HAS_GSS_FRAMEWORK
#include <GSS/GSS.h>
#else

/*
* Starting in macOS 10.7, Apple's GSS defines these in
* gssapi_private.h. However, that header isn't present on the host, so we
* need to explicitly define them. The originals can be found at:
* https://opensource.apple.com/source/Heimdal/Heimdal-172.18/lib/gssapi/gssapi/gssapi_spi.h.auto.html
*/

OM_uint32 __ApplePrivate_gss_unwrap_iov(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
int *conf_state, gss_qop_t *qop_state,
gss_iov_buffer_desc *iov,
int iov_count);

OM_uint32 __ApplePrivate_gss_wrap_iov(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
int conf_req_flag, gss_qop_t qop_req,
int *conf_state,
gss_iov_buffer_desc *iov,
int iov_count);

OM_uint32 __ApplePrivate_gss_wrap_iov_length(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req,
int *conf_state,
gss_iov_buffer_desc *iov,
int iov_count);

OM_uint32 __ApplePrivate_gss_release_iov_buffer(OM_uint32 *minor_status,
gss_iov_buffer_desc *iov,
int iov_count);

#else /* !OSX_HAS_GSS_FRAMEWORK */

#if defined(__MINGW32__) && defined(__MSYS__)
#include <gss.h>
#else
Expand All @@ -10,4 +44,5 @@
#include <gssapi/gssapi.h>
#endif
#endif
#endif

#endif /* !OSX_HAS_GSS_FRAMEWORK */
Loading

0 comments on commit 2bccab4

Please sign in to comment.