Skip to content

Commit 175cfe5

Browse files
committed
Add high-level Security Context API
1 parent 8180ddf commit 175cfe5

13 files changed

Lines changed: 677 additions & 116 deletions

gssapi/_utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,28 @@ def import_gssapi_extension(name):
88
return sys.modules[path]
99
except ImportError:
1010
return None
11+
12+
13+
def flag_property(flag):
14+
def setter(self, val):
15+
if val:
16+
self.flags.add(flag)
17+
else:
18+
self.flags.discard(flag)
19+
20+
def getter(self):
21+
return flag in self.flags
22+
23+
return property(getter, setter)
24+
25+
26+
def inquire_property(name):
27+
def inquire_property(self):
28+
if not self._started:
29+
msg = ("Cannot read {0} from a security context whose "
30+
"establishment has not yet been started.")
31+
raise AttributeError(msg)
32+
33+
return getattr(self._inquire(**{name: True}), name)
34+
35+
return property(inquire_property)

gssapi/exceptions.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# non-GSS exceptions
2+
class GeneralError(Exception):
3+
MAJOR_MESSAGE = "General error"
4+
FMT_STR = "{maj}: {min}."
5+
6+
def __init__(self, minor_message, **kwargs):
7+
maj_str = self.MAJOR_MESSAGE.format(**kwargs)
8+
err_str = self.FMT_STR.format(maj=maj_str, min=minor_message)
9+
super(GeneralError, self).__init__(err_str)
10+
11+
12+
class UnknownUsageError(GeneralError):
13+
MAJOR_MESSAGE = "Unable to determine {obj} usage"
14+
15+
16+
class EncryptionNotUsed(GeneralError):
17+
MAJOR_MESSAGE = "Confidentiality was requested, but not used"

gssapi/raw/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from gssapi.raw.misc import * # noqa
44
from gssapi.raw.names import * # noqa
55
from gssapi.raw.sec_contexts import * # noqa
6+
from gssapi.raw.oids import * # noqa
67
from gssapi.raw.types import * # noqa
78

89
# optional S4U support

gssapi/raw/cython_converters.pxd

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,34 @@
1+
from libc.string cimport memcmp
2+
13
from gssapi.raw.cython_types cimport gss_OID, gss_OID_set, gss_OID_desc
24
from gssapi.raw.cython_types cimport OM_uint32
5+
from gssapi.raw.cython_types cimport GSS_C_INDEFINITE
36

47
from gssapi.raw.types import MechType, NameType
58

69

710
cdef gss_OID_set c_get_mech_oid_set(object mechs)
811
cdef inline bint c_compare_oids(gss_OID a, gss_OID b)
912
cdef object c_create_mech_list(gss_OID_set mech_set, bint free=*)
10-
cdef inline OM_uint32 c_py_ttl_to_c(object ttl)
11-
cdef inline object c_c_ttl_to_py(OM_uint32 ttl)
13+
14+
cdef inline OM_uint32 c_py_ttl_to_c(object ttl) except? 1:
15+
"""Converts None to GSS_C_INDEFINITE, otherwise returns input."""
16+
if ttl is None:
17+
return GSS_C_INDEFINITE
18+
else:
19+
return <OM_uint32>ttl
20+
21+
22+
cdef inline object c_c_ttl_to_py(OM_uint32 ttl):
23+
"""Converts GSS_C_INDEFINITE to None, otherwise return input."""
24+
if ttl == GSS_C_INDEFINITE:
25+
return None
26+
else:
27+
return ttl
28+
29+
30+
cdef inline bint c_compare_oids(gss_OID a, gss_OID b):
31+
"""Compare two OIDs to see if they are the same."""
32+
33+
return (a.length == b.length and
34+
not memcmp(a.elements, b.elements, a.length))

gssapi/raw/cython_converters.pyx

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from libc.string cimport memcmp
2-
31
from gssapi.raw.cython_types cimport *
42
from gssapi.raw.oids cimport OID
53

@@ -21,13 +19,6 @@ cdef gss_OID_set c_get_mech_oid_set(object mechs):
2119
return res_set
2220

2321

24-
cdef inline bint c_compare_oids(gss_OID a, gss_OID b):
25-
"""Compare two OIDs to see if they are the same."""
26-
27-
return (a.length == b.length and
28-
not memcmp(a.elements, b.elements, a.length))
29-
30-
3122
cdef object c_create_mech_list(gss_OID_set mech_set, bint free=True):
3223
"""Convert a set of GSS mechanism OIDs to a list of MechType values."""
3324

@@ -43,19 +34,3 @@ cdef object c_create_mech_list(gss_OID_set mech_set, bint free=True):
4334
gss_release_oid_set(&tmp_min_stat, &mech_set)
4435

4536
return l
46-
47-
48-
cdef inline OM_uint32 c_py_ttl_to_c(object ttl):
49-
"""Converts None to GSS_C_INDEFINITE, otherwise returns input."""
50-
if ttl is None:
51-
return GSS_C_INDEFINITE
52-
else:
53-
return <OM_uint32>ttl
54-
55-
56-
cdef inline object c_c_ttl_to_py(OM_uint32 ttl):
57-
"""Converts GSS_C_INDEFINITE to None, otherwise return input."""
58-
if ttl == GSS_C_INDEFINITE:
59-
return None
60-
else:
61-
return ttl

gssapi/raw/cython_types.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ cdef extern from "gssapi.h":
104104
OM_uint32 GSS_C_INTEG_FLAG
105105
OM_uint32 GSS_C_ANON_FLAG
106106
OM_uint32 GSS_C_TRANS_FLAG
107+
OM_uint32 GSS_C_PROT_READY_FLAG
107108

108109

109110
cdef extern from "gssapi/gssapi_krb5.h":

gssapi/raw/message.pyx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ from gssapi.raw.cython_types cimport *
44
from gssapi.raw.sec_contexts cimport SecurityContext
55

66
from gssapi.raw.misc import GSSError
7+
from gssapi.raw.named_tuples import VerifyMICResult, WrapResult, UnwrapResult
78

89

910
cdef extern from "gssapi.h":
@@ -136,12 +137,12 @@ def verifyMIC(SecurityContext context not None, message, token,
136137

137138
if maj_stat == GSS_S_COMPLETE or maj_stat == GSS_S_DUPLICATE_TOKEN:
138139
if return_bool:
139-
return (True, qop_state, maj_stat, min_stat)
140+
return VerifyMICResult(True, qop_state, maj_stat, min_stat)
140141
else:
141142
return qop_state
142143
else:
143144
if return_bool:
144-
return (False, qop_state, maj_stat, min_stat)
145+
return VerifyMICResult(False, qop_state, maj_stat, min_stat)
145146
else:
146147
raise GSSError(maj_stat, min_stat)
147148

@@ -229,7 +230,7 @@ def wrap(SecurityContext context not None, message, confidential=True,
229230
if maj_stat == GSS_S_COMPLETE:
230231
output_message = output_buffer.value[:output_buffer.length]
231232
gss_release_buffer(&min_stat, &output_buffer)
232-
return (output_message, <bint>conf_used)
233+
return WrapResult(output_message, <bint>conf_used)
233234

234235

235236
def unwrap(SecurityContext context not None, message):
@@ -269,6 +270,6 @@ def unwrap(SecurityContext context not None, message):
269270
if maj_stat == GSS_S_COMPLETE:
270271
output_message = output_buffer.value[:output_buffer.length]
271272
gss_release_buffer(&min_stat, &output_buffer)
272-
return (output_message, <bint>conf_state, qop_state)
273+
return UnwrapResult(output_message, <bint>conf_state, qop_state)
273274
else:
274275
raise GSSError(maj_stat, min_stat)

gssapi/raw/named_tuples.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,37 @@
2121
['mechs', 'init_lifetime',
2222
'accept_lifetime'])
2323

24+
2425
DisplayNameResult = namedtuple('DisplayNameResult',
2526
['name', 'name_type'])
27+
28+
29+
VerifyMICResult = namedtuple('VerifyMICResult',
30+
['valid', 'qop', 'major_status',
31+
'minor_status'])
32+
33+
34+
# TODO(directxman12): should this be 'encrypted' or 'confidential'?
35+
WrapResult = namedtuple('WrapResult',
36+
['message', 'encrypted'])
37+
38+
39+
UnwrapResult = namedtuple('UnwrapResult',
40+
['message', 'encrypted', 'qop'])
41+
42+
43+
AcceptSecContextResult = namedtuple('AcceptSecContextResult',
44+
['context', 'initiator_name',
45+
'mech_type', 'token', 'flags', 'lifetime',
46+
'delegated_creds', 'more_steps'])
47+
48+
49+
InitSecContextResult = namedtuple('InitSecContextResult',
50+
['context', 'mech_type', 'flags', 'token',
51+
'lifetime', 'more_steps'])
52+
53+
54+
InquireContextResult = namedtuple('InquireContextResult',
55+
['initiator_name', 'target_name',
56+
'lifetime', 'mech_type', 'flags',
57+
'locally_init', 'complete'])

0 commit comments

Comments
 (0)