Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support DCE IOV functions on macOS #258

Merged
merged 1 commit into from
Aug 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
frozencemetery marked this conversation as resolved.
Show resolved Hide resolved
#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