Skip to content

Commit

Permalink
Handle MIC/Wrap security layers correctly even if no user is given
Browse files Browse the repository at this point in the history
This is obviously cut&copied all over the net. (found nearly identical
code including comments in the mutt email client, the upstream
calendarserver/pykerberos code and a few other places).

And it is wrong if 'user' is empty.

RFC 4752 Section 3.1 states the responsibilities of the client side a
SASL GSSAPI Authentication.

We get the last package from the server in this step, and have to
GSS_Unwrap() and inspect the security_layer offerings of the server.

This is done and logged here (even if not perfect).

Once the offered security layers are known, the client has to send the
one used.

In the code before the patch this was kind of ok (GSS_AUTH_P_NONE) for
the case when there is a authorization ID given, but broken for the case
when no user was given.

The code just replied with anything the server offers, even if totally
unable to handle that, which leads to errors if the established security
context is used for further communication (e.g. in LDAP).

In addition, these options should be synced with the gssflags of the
context, e.g. fail if the server does not honour the requested security.
(not that it makes any sense to request any higher security, as the
client doesn't handle it.)
  • Loading branch information
Michael Schlenker committed Feb 4, 2016
1 parent 247f9f5 commit 4cd02b5
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions kerberos_sspi.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,17 +275,26 @@ def authGSSClientWrap(context, data, user=None):

data = decodestring(data) if data else None
# RFC 4752 Section 3.1 last 2 paragraphs
if user and data:
if data:
import struct
conf_and_size = data[:struct.calcsize("!L")] # network unsigned long
conf = struct.unpack("B", conf_and_size[0])[0] # B .. unsigned char
size = struct.unpack("!L", conf_and_size)[0] & 0x00ffffff
logger.info("N" if conf & GSS_AUTH_P_NONE else "-")
logger.info("I" if conf & GSS_AUTH_P_INTEGRITY else "-")
logger.info("P" if conf & GSS_AUTH_P_PRIVACY else "-")
logger.info("Maximum GSS token size is %d", size)
conf_and_size=chr(GSS_AUTH_P_NONE) + conf_and_size[1:]
data = conf_and_size + user.encode("utf-8")
logger.info("Maximum GSS message size for server side is %d", size)
# Tell the truth, we do not handle any security layer
# (aka GSS_AUTH_P_NONE). RFC 4752 demands that the
# max client message size is zero in this case.
max_size_client_message = 0
security_layer = GSS_AUTH_P_NONE
conf_and_size = struct.pack("!L", security_layer << 24 +
(max_size_client_message & 0x00ffffff))
if user:
data = conf_and_size + user.encode("utf-8")
else:
data = conf_and_size

pkg_size_info=ca.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
trailersize=pkg_size_info['SecurityTrailer']
Expand Down

0 comments on commit 4cd02b5

Please sign in to comment.