kdc: support for GSS-API pre-authentication
Add support for GSS-API pre-authentication to the KDC, using a simplified variation of draft-perez-krb-wg-gss-preauth-02 that encodes GSS-API context tokens directly in PADATA, and uses FX-COOKIE for state management. More information on the protocol and implementation may be found in lib/gssapi/preauth/README.md.
This commit is contained in:
@@ -13,6 +13,7 @@ AM_CPPFLAGS += \
|
||||
-I$(srcdir)/krb5 \
|
||||
-I$(srcdir)/spnego \
|
||||
-I$(srcdir)/sanon \
|
||||
-I$(srcdir)/preauth \
|
||||
$(INCLUDE_libintl)
|
||||
|
||||
lib_LTLIBRARIES = libgssapi.la test_negoex_mech.la
|
||||
@@ -250,12 +251,17 @@ sanonsrc = \
|
||||
sanon/release_name.c \
|
||||
sanon/sanon-private.h
|
||||
|
||||
preauthsrc = \
|
||||
preauth/pa_client.c \
|
||||
preauth/pa_common.c
|
||||
|
||||
dist_libgssapi_la_SOURCES = \
|
||||
$(krb5src) \
|
||||
$(mechsrc) \
|
||||
$(ntlmsrc) \
|
||||
$(spnegosrc) \
|
||||
$(sanonsrc)
|
||||
$(sanonsrc) \
|
||||
$(preauthsrc)
|
||||
|
||||
nodist_libgssapi_la_SOURCES = \
|
||||
gkrb5_err.c \
|
||||
@@ -289,6 +295,7 @@ noinst_HEADERS = \
|
||||
$(srcdir)/ntlm/ntlm-private.h \
|
||||
$(srcdir)/spnego/spnego-private.h \
|
||||
$(srcdir)/sanon/sanon-private.h \
|
||||
$(srcdir)/preauth/pa-private.h \
|
||||
$(srcdir)/krb5/gsskrb5-private.h
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
@@ -296,6 +303,7 @@ nobase_include_HEADERS = \
|
||||
gssapi/gssapi_krb5.h \
|
||||
gssapi/gssapi_ntlm.h \
|
||||
gssapi/gssapi_oid.h \
|
||||
gssapi/gssapi_preauth.h \
|
||||
gssapi/gssapi_spnego.h
|
||||
|
||||
gssapidir = $(includedir)/gssapi
|
||||
@@ -319,7 +327,8 @@ BUILTHEADERS = \
|
||||
$(srcdir)/krb5/gsskrb5-private.h \
|
||||
$(srcdir)/spnego/spnego-private.h \
|
||||
$(srcdir)/sanon/sanon-private.h \
|
||||
$(srcdir)/ntlm/ntlm-private.h
|
||||
$(srcdir)/ntlm/ntlm-private.h \
|
||||
$(srcdir)/preauth/pa-private.h
|
||||
|
||||
$(libgssapi_la_OBJECTS): $(BUILTHEADERS)
|
||||
$(test_context_OBJECTS): $(BUILTHEADERS)
|
||||
@@ -356,6 +365,9 @@ $(srcdir)/spnego/spnego-private.h:
|
||||
$(srcdir)/sanon/sanon-private.h:
|
||||
cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p sanon/sanon-private.h $(sanonsrc) || rm -f sanon/sanon-private.h
|
||||
|
||||
$(srcdir)/preauth/pa-private.h:
|
||||
cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p preauth/pa-private.h $(preauthsrc) || rm -f preauth/pa-private.h
|
||||
|
||||
TESTS = test_oid test_names test_cfx
|
||||
# test_sequence
|
||||
|
||||
|
@@ -261,6 +261,10 @@ sanonsrc = \
|
||||
sanon/release_cred.c \
|
||||
sanon/release_name.c
|
||||
|
||||
preauthsrc = \
|
||||
preauth/pa_client.c \
|
||||
preauth/pa_common.c
|
||||
|
||||
$(OBJ)\ntlm\ntlm-private.h: $(ntlmsrc)
|
||||
$(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(ntlmsrc)
|
||||
|
||||
@@ -273,6 +277,9 @@ $(OBJ)\spnego\spnego-private.h: $(spnegosrc)
|
||||
$(OBJ)\sanon\sanon-private.h: $(sanonsrc)
|
||||
$(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(sanonsrc)
|
||||
|
||||
$(OBJ)\preauth\pa-private.h: $(preauthsrc)
|
||||
$(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(preauthsrc)
|
||||
|
||||
gssapi_files = $(OBJ)\gssapi\asn1_gssapi_asn1.x
|
||||
|
||||
spnego_files = $(OBJ)\spnego\asn1_spnego_asn1.x
|
||||
@@ -317,6 +324,7 @@ INCFILES= \
|
||||
$(OBJ)\ntlm\ntlm-private.h \
|
||||
$(OBJ)\spnego\spnego-private.h \
|
||||
$(OBJ)\sanon\sanon-private.h \
|
||||
$(OBJ)\preauth\pa-private.h \
|
||||
$(OBJ)\krb5\gsskrb5-private.h \
|
||||
$(OBJ)\gkrb5_err.h \
|
||||
$(OBJ)\negoex_err.h \
|
||||
@@ -533,6 +541,8 @@ libgssapi_OBJs = \
|
||||
$(OBJ)\sanon/process_context_token.obj \
|
||||
$(OBJ)\sanon/release_cred.obj \
|
||||
$(OBJ)\sanon/release_name.obj \
|
||||
$(OBJ)\preauth/pa_client.obj \
|
||||
$(OBJ)\preauth/pa_common.obj \
|
||||
$(OBJ)\gkrb5_err.obj \
|
||||
$(OBJ)\negoex_err.obj \
|
||||
$(spnego_files:.x=.obj) \
|
||||
@@ -570,6 +580,12 @@ GCOPTS=-I$(SRCDIR) -I$(OBJ) -Igssapi -DBUILD_GSSAPI_LIB
|
||||
{sanon}.c{$(OBJ)\sanon}.obj::
|
||||
$(C2OBJ_NP) -Fo$(OBJ)\sanon\ -Fd$(OBJ)\sanon\ -I$(OBJ)\sanon -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS) -DASN1_LIB
|
||||
|
||||
{$(OBJ)\preauth}.c{$(OBJ)\preauth}.obj::
|
||||
$(C2OBJ_NP) -Fo$(OBJ)\preauth\ -Fd$(OBJ)\pa\ -I$(OBJ)\pa -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS)
|
||||
|
||||
{preauth}.c{$(OBJ)\preauth}.obj::
|
||||
$(C2OBJ_NP) -Fo$(OBJ)\preauth\ -Fd$(OBJ)\pa\ -I$(OBJ)\pa -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS) -DASN1_LIB
|
||||
|
||||
{$(OBJ)\gssapi}.c{$(OBJ)\gssapi}.obj::
|
||||
$(C2OBJ_NP) -Fo$(OBJ)\gssapi\ -Fd$(OBJ)\gssapi\ -I$(OBJ)\gssapi $(GCOPTS)
|
||||
|
||||
@@ -660,6 +676,9 @@ mkdirs-gss:
|
||||
!if !exist($(OBJ)\gssapi)
|
||||
$(MKDIR) $(OBJ)\gssapi
|
||||
!endif
|
||||
!if !exist($(OBJ)\preauth)
|
||||
$(MKDIR) $(OBJ)\preauth
|
||||
!endif
|
||||
|
||||
clean::
|
||||
-$(RM) $(OBJ)\ntlm\*.*
|
||||
@@ -668,6 +687,7 @@ clean::
|
||||
-$(RM) $(OBJ)\mech\*.*
|
||||
-$(RM) $(OBJ)\sanon\*.*
|
||||
-$(RM) $(OBJ)\gssapi\*.*
|
||||
-$(RM) $(OBJ)\preauth\*.*
|
||||
|
||||
all-tools:: $(BINDIR)\gsstool.exe
|
||||
|
||||
|
@@ -1240,6 +1240,9 @@ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
|
||||
gss_destroy_cred(OM_uint32 *minor_status,
|
||||
gss_cred_id_t *cred_handle);
|
||||
|
||||
GSSAPI_LIB_FUNCTION uintptr_t GSSAPI_CALLCONV
|
||||
gss_get_instance(const char *libname);
|
||||
|
||||
GSSAPI_CPP_END
|
||||
|
||||
#if defined(__APPLE__) && (defined(__ppc__) || defined(__ppc64__) || defined(__i386__) || defined(__x86_64__))
|
||||
|
55
lib/gssapi/gssapi/gssapi_preauth.h
Normal file
55
lib/gssapi/gssapi/gssapi_preauth.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef GSSAPI_PREAUTH_H_
|
||||
#define GSSAPI_PREAUTH_H_
|
||||
|
||||
#include <gssapi.h>
|
||||
#include <krb5.h>
|
||||
|
||||
GSSAPI_CPP_START
|
||||
|
||||
#if !defined(__GNUC__) && !defined(__attribute__)
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
GSSAPI_LIB_FUNCTION krb5_error_code GSSAPI_LIB_CALL
|
||||
krb5_gss_set_init_creds(krb5_context context,
|
||||
krb5_init_creds_context ctx,
|
||||
gss_const_cred_id_t gss_cred,
|
||||
gss_const_OID gss_mech);
|
||||
|
||||
|
||||
#endif /* GSSAPI_PREAUTH_H_ */
|
@@ -40,6 +40,7 @@ EXPORTS
|
||||
gss_export_name
|
||||
gss_export_name_composite
|
||||
gss_export_sec_context
|
||||
gss_get_instance
|
||||
gss_get_mic
|
||||
gss_get_neg_mechs
|
||||
gss_get_name_attribute
|
||||
@@ -122,6 +123,14 @@ EXPORTS
|
||||
gsskrb5_set_send_to_kdc
|
||||
gsskrb5_set_time_offset
|
||||
krb5_gss_register_acceptor_identity
|
||||
krb5_gss_set_init_creds
|
||||
|
||||
_krb5_gss_data_to_buffer
|
||||
_krb5_gss_buffer_to_data
|
||||
_krb5_gss_map_error
|
||||
_krb5_gss_pa_parse_name
|
||||
_krb5_gss_pa_unparse_name
|
||||
_krb5_gss_pa_derive_key
|
||||
|
||||
; _gsskrb5cfx_ are really internal symbols, but export
|
||||
; then now to make testing easier.
|
||||
|
@@ -563,3 +563,16 @@ gss_oid_to_name(gss_const_OID oid)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GSSAPI_LIB_FUNCTION uintptr_t GSSAPI_CALLCONV
|
||||
gss_get_instance(const char *libname)
|
||||
{
|
||||
static const char *instance = "libgssapi";
|
||||
|
||||
if (strcmp(libname, "gssapi") == 0)
|
||||
return (uintptr_t)instance;
|
||||
else if (strcmp(libname, "krb5") == 0)
|
||||
return krb5_get_instance(libname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
119
lib/gssapi/preauth/README.md
Normal file
119
lib/gssapi/preauth/README.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# GSS-API Pre-authentication in Heimdal
|
||||
|
||||
GSS-API pre-authentication in Heimdal is based on
|
||||
[draft-perez-krb-wg-gss-preauth](https://datatracker.ietf.org/doc/html/draft-perez-krb-wg-gss-preauth)
|
||||
but with some simplifications to the protocol.
|
||||
|
||||
The following text assumes the reader is familiar with the draft.
|
||||
|
||||
## Protocol changes
|
||||
|
||||
- The pre-authentication type KRB5-PADATA-GSS is 655
|
||||
- Pre-authentication data is the raw context token rather than being
|
||||
wrapped in another ASN.1 type
|
||||
- Acceptor GSS state is stored in FX-COOKIE rather than alongside the
|
||||
context token
|
||||
- Key derivation salt is the string "KRB-GSS\0" || nonce
|
||||
|
||||
## Client side
|
||||
|
||||
Because libkrb5 cannot have a recursive dependency on libgssapi, it instead
|
||||
exports the function `_krb5_init_creds_init_gss()` which allows libgssapi to
|
||||
register a set of function pointers for:
|
||||
|
||||
- Generating context tokens
|
||||
- Finalizing a context (inquiring the initiator name and reply key)
|
||||
- Releasing context and credential handles
|
||||
|
||||
This is a private API.
|
||||
|
||||
This architecture also means that the libkrb5 implementation could be used with
|
||||
an alternative GSS-API implementation such as SSPI, without too much work. The
|
||||
bulk of the pre-authentication logic remains in libkrb5, however, in
|
||||
[`init_creds_pw.c`](../../krb5/init_creds_pw.c).
|
||||
|
||||
libgssapi itself exports `krb5_gss_set_init_creds()`, which is the public
|
||||
interface for GSS-API pre-authentication.
|
||||
|
||||
`krb5_gss_set_init_creds()` enables GSS-API pre-authentication on an initial
|
||||
credentials context, taking a GSS-API credential handle and mechanism. Both are
|
||||
optional; defaults will be used if absent. These two parameters are exposed as
|
||||
the `--gss-name` and `--gss-mech` options to `kinit` (see
|
||||
[kinit(1)](../../../kuser/kinit.1) for further details). `kinit` supports
|
||||
acquiring anonymous, keytab- and password-based GSS-API credentials using the
|
||||
same arguments as regular Kerberos.
|
||||
|
||||
The selected GSS-API mechanism must support mutual authentication (ie.
|
||||
authenticating the KDC) as it replaces the AS-REP reply key, However, if FAST
|
||||
was used, and we know that the KDC was verified, then this requirement is
|
||||
removed.
|
||||
|
||||
If the client does not know its initiator name, it can specify the last
|
||||
arugment to `kinit` as `@REALM`, and the initiator name will be filled in when
|
||||
the authentication is complete. (The realm is required to select a KDC.)
|
||||
|
||||
## KDC side
|
||||
|
||||
The KDC implements the acceptor side of the GSS-API authentication exchange.
|
||||
The selected GSS-API mechanism must allow `gss_export_sec_context()` to be
|
||||
called by the acceptor before the context is established, if it needs more than
|
||||
a single round trip of token exchanges.
|
||||
|
||||
### Configuration
|
||||
|
||||
Configuration directives live in the [kdc] section of
|
||||
[krb5.conf(5)](../../krb5/krb5.conf.5).
|
||||
|
||||
The `enable_gss_preauth` krb5.conf option must be set in order to enable
|
||||
GSS-API pre-authentication in the KDC. When authenticating federated principals
|
||||
which may not exist in the KDC, the `synthetic_clients` option should also be
|
||||
set.
|
||||
|
||||
The `gss_mechanisms_allowed` option can be used to limit the set of GSS-API
|
||||
mechanisms which are allowed to perform pre-authentication. Mechanisms are
|
||||
specified as dot-separated OIDs or by a short name, such as `sanon-x25519`.
|
||||
|
||||
The `enable_gss_auth_data` option will include a composite GSS name in the
|
||||
authorization data of returned tickets.
|
||||
|
||||
### Authorization
|
||||
|
||||
The default is that the initiator is permitted to authenticate to the Kerberos
|
||||
principal that directly corresponds to it. The correspondence is governed as
|
||||
follows: if the authenticating mechanism is in the list of mechanisms in the
|
||||
`gss_cross_realm_mechanisms_allowed` configuration option, then the principal
|
||||
is mapped identically: an initiator named `lukeh@AAA.PADL.COM` will be mapped
|
||||
to the Kerberos principal `lukeh@AAA.PADL.COM`.
|
||||
|
||||
If the authenticating mechanism is not in this list, then the initiator will be
|
||||
mapped to an enterprise principal in the service realm. For example,
|
||||
`lukeh@AAA.PADL.COM` might be mapped to `lukeh\@AAA.PADL.COM@PADL.COM`
|
||||
(enterprise principal name type);
|
||||
|
||||
This mapping has no effect for principals that exist in the HDB, because
|
||||
enterprise principal names are always looked up by their first component (as if
|
||||
they were an ordinary principal name). This logic is instead useful when
|
||||
synthetic principals are enabled as we wish to avoid issuing tickets with a
|
||||
client name in a foreign Kerberos realm, as that would conflate GSS-API
|
||||
"realms" with Kerberos realms.
|
||||
|
||||
A custom authorization plugin installed in `$prefix/lib/plugin/kdc` will
|
||||
replace this mapping and authorization logic. The plugin interface is defined in
|
||||
[`gss_preauth_authorizer_plugin.h`](../../../kdc/gss_preauth_authorizer_plugin.h)).
|
||||
|
||||
### Anonymous authentication
|
||||
|
||||
A further note on the interaction of anonymous GSS-API authentication and
|
||||
pre-authentication. Initiator contexts that set `GSS_C_ANON_FLAG` and a
|
||||
`GSS_C_NT_ANONYMOUS` name are mapped to the unauthenticated anonymous Kerberos
|
||||
principal, `WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS`. However, the local
|
||||
`WELLKNOWN/ANONYMOUS` HDB entry is used to perform any authorization decisions
|
||||
(as it would be for anonymous PKINIT). The AP-REP will contain the well-known
|
||||
anonymous realm.
|
||||
|
||||
If `GSS_C_NT_ANONYMOUS` was set but a different name type was returned, then
|
||||
the initiator is treated as authenticated anonymous, and the client realm will
|
||||
be present in the AP-REP.
|
||||
|
||||
The `request-anonymous` AP-REQ flag must also be set for GSS-API anonymous
|
||||
authentication to succeed.
|
251
lib/gssapi/preauth/pa_client.c
Normal file
251
lib/gssapi/preauth/pa_client.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2021, PADL Software Pty Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of PADL Software nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "krb5_locl.h"
|
||||
#include "mech_locl.h"
|
||||
|
||||
#include <gssapi/gssapi_preauth.h>
|
||||
|
||||
#include <preauth/pa-private.h>
|
||||
|
||||
static krb5_error_code
|
||||
pa_gss_acquire_initiator_cred(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
const krb5_creds *kcred,
|
||||
gss_cred_id_t *cred)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_const_OID mech;
|
||||
gss_OID_set_desc mechs;
|
||||
gss_name_t initiator_name = GSS_C_NO_NAME;
|
||||
OM_uint32 time_req;
|
||||
krb5_timestamp now;
|
||||
|
||||
*cred = GSS_C_NO_CREDENTIAL;
|
||||
|
||||
mech = _krb5_init_creds_get_gss_mechanism(context, gssic);
|
||||
|
||||
mechs.count = 1;
|
||||
mechs.elements = (gss_OID)mech;
|
||||
|
||||
ret = _krb5_gss_pa_unparse_name(context, kcred->client, &initiator_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
krb5_timeofday(context, &now);
|
||||
if (kcred->times.endtime && kcred->times.endtime > now)
|
||||
time_req = kcred->times.endtime - now;
|
||||
else
|
||||
time_req = GSS_C_INDEFINITE;
|
||||
|
||||
major = gss_acquire_cred(&minor, initiator_name, time_req, &mechs,
|
||||
GSS_C_INITIATE, cred, NULL, NULL);
|
||||
ret = _krb5_gss_map_error(major, minor);
|
||||
|
||||
gss_release_name(&major, &initiator_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code KRB5_LIB_CALL
|
||||
pa_gss_step(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
const krb5_creds *kcred,
|
||||
KDCOptions flags,
|
||||
krb5_data *enc_as_req,
|
||||
krb5_data *in,
|
||||
krb5_data *out)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_cred_id_t cred;
|
||||
gss_ctx_id_t ctx;
|
||||
gss_name_t target_name = GSS_C_NO_NAME;
|
||||
OM_uint32 req_flags = GSS_C_MUTUAL_FLAG;
|
||||
OM_uint32 ret_flags;
|
||||
struct gss_channel_bindings_struct cb = { 0 };
|
||||
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
krb5_data_zero(out);
|
||||
|
||||
if (flags.request_anonymous)
|
||||
req_flags |= GSS_C_ANON_FLAG;
|
||||
|
||||
cred = (gss_cred_id_t)_krb5_init_creds_get_gss_cred(context, gssic);
|
||||
|
||||
if (cred == GSS_C_NO_CREDENTIAL) {
|
||||
ret = pa_gss_acquire_initiator_cred(context, gssic, kcred, &cred);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
_krb5_init_creds_set_gss_cred(context, gssic, cred);
|
||||
}
|
||||
|
||||
ctx = (gss_ctx_id_t)_krb5_init_creds_get_gss_context(context, gssic);
|
||||
|
||||
ret = _krb5_gss_pa_unparse_name(context, kcred->server, &target_name);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
_krb5_gss_data_to_buffer(enc_as_req, &cb.application_data);
|
||||
_krb5_gss_data_to_buffer(in, &input_token);
|
||||
|
||||
major = gss_init_sec_context(&minor,
|
||||
cred,
|
||||
&ctx,
|
||||
target_name,
|
||||
(gss_OID)_krb5_init_creds_get_gss_mechanism(context, gssic),
|
||||
req_flags,
|
||||
GSS_C_INDEFINITE,
|
||||
&cb,
|
||||
&input_token,
|
||||
NULL,
|
||||
&output_token,
|
||||
&ret_flags,
|
||||
NULL);
|
||||
|
||||
_krb5_init_creds_set_gss_context(context, gssic, ctx);
|
||||
|
||||
_krb5_gss_buffer_to_data(&output_token, out);
|
||||
_mg_buffer_zero(&output_token);
|
||||
|
||||
if (major == GSS_S_COMPLETE) {
|
||||
if ((ret_flags & GSS_C_MUTUAL_FLAG) == 0)
|
||||
ret = KRB5_MUTUAL_FAILED;
|
||||
else if ((ret_flags & req_flags) != req_flags)
|
||||
ret = KRB5KDC_ERR_BADOPTION;
|
||||
else
|
||||
ret = 0;
|
||||
} else
|
||||
ret = _krb5_gss_map_error(major, minor);
|
||||
|
||||
out:
|
||||
gss_release_name(&minor, &target_name);
|
||||
gss_release_buffer(&minor, &output_token);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code KRB5_LIB_CALL
|
||||
pa_gss_finish(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
const krb5_creds *kcred,
|
||||
krb5int32 nonce,
|
||||
krb5_enctype enctype,
|
||||
krb5_principal *client_p,
|
||||
krb5_keyblock **reply_key_p)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_principal client = NULL;
|
||||
krb5_keyblock *reply_key = NULL;
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_name_t initiator_name = GSS_C_NO_NAME;
|
||||
gss_ctx_id_t ctx = (gss_ctx_id_t)_krb5_init_creds_get_gss_context(context, gssic);
|
||||
|
||||
*client_p = NULL;
|
||||
*reply_key_p = NULL;
|
||||
|
||||
major = gss_inquire_context(&minor,
|
||||
ctx,
|
||||
&initiator_name,
|
||||
NULL, /* target_name */
|
||||
NULL, /* lifetime_req */
|
||||
NULL, /* mech_type */
|
||||
NULL, /* ctx_flags */
|
||||
NULL, /* locally_initiated */
|
||||
NULL); /* open */
|
||||
|
||||
if (GSS_ERROR(major))
|
||||
return _krb5_gss_map_error(major, minor);
|
||||
|
||||
ret = _krb5_gss_pa_parse_name(context, initiator_name, 0, &client);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = _krb5_gss_pa_derive_key(context, ctx, nonce, enctype, &reply_key);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
*client_p = client;
|
||||
client = NULL;
|
||||
|
||||
*reply_key_p = reply_key;
|
||||
reply_key = NULL;
|
||||
|
||||
out:
|
||||
krb5_free_principal(context, client);
|
||||
if (reply_key)
|
||||
krb5_free_keyblock(context, reply_key);
|
||||
gss_release_name(&minor, &initiator_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void KRB5_LIB_CALL
|
||||
pa_gss_delete_sec_context(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
gss_ctx_id_t ctx)
|
||||
{
|
||||
OM_uint32 minor;
|
||||
|
||||
gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
|
||||
}
|
||||
|
||||
static void KRB5_LIB_CALL
|
||||
pa_gss_release_cred(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
gss_cred_id_t cred)
|
||||
{
|
||||
OM_uint32 minor;
|
||||
|
||||
gss_release_cred(&minor, &cred);
|
||||
}
|
||||
|
||||
GSSAPI_LIB_FUNCTION krb5_error_code GSSAPI_LIB_CALL
|
||||
krb5_gss_set_init_creds(krb5_context context,
|
||||
krb5_init_creds_context ctx,
|
||||
gss_const_cred_id_t gss_cred,
|
||||
gss_const_OID gss_mech)
|
||||
{
|
||||
return _krb5_init_creds_init_gss(context,ctx,
|
||||
pa_gss_step,
|
||||
pa_gss_finish,
|
||||
pa_gss_release_cred,
|
||||
pa_gss_delete_sec_context,
|
||||
gss_cred,
|
||||
gss_mech,
|
||||
0);
|
||||
}
|
215
lib/gssapi/preauth/pa_common.c
Normal file
215
lib/gssapi/preauth/pa_common.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2021, PADL Software Pty Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of PADL Software nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "krb5_locl.h"
|
||||
#include "mech_locl.h"
|
||||
|
||||
#include <gssapi/gssapi_preauth.h>
|
||||
|
||||
#include <preauth/pa-private.h>
|
||||
|
||||
krb5_error_code
|
||||
_krb5_gss_map_error(OM_uint32 major, OM_uint32 minor)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
if (minor != 0)
|
||||
return (krb5_error_code)minor;
|
||||
|
||||
switch (major) {
|
||||
case GSS_S_COMPLETE:
|
||||
ret = 0;
|
||||
break;
|
||||
case GSS_S_CONTINUE_NEEDED:
|
||||
ret = KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;
|
||||
break;
|
||||
case GSS_S_BAD_NAME:
|
||||
case GSS_S_BAD_NAMETYPE:
|
||||
ret = KRB5_PRINC_NOMATCH;
|
||||
break;
|
||||
case GSS_S_BAD_MIC:
|
||||
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||||
break;
|
||||
case GSS_S_FAILURE:
|
||||
default:
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_gss_pa_derive_key(krb5_context context,
|
||||
gss_ctx_id_t ctx,
|
||||
krb5int32 nonce,
|
||||
krb5_enctype enctype,
|
||||
krb5_keyblock **keyblock)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
u_char saltdata[12] = "KRB-GSS";
|
||||
krb5_keyblock kdkey;
|
||||
size_t keysize;
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_buffer_desc salt, dkey = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
*keyblock = NULL;
|
||||
|
||||
ret = krb5_enctype_keysize(context, enctype, &keysize);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
_gss_mg_encode_le_uint32(nonce, &saltdata[8]);
|
||||
|
||||
salt.value = saltdata;
|
||||
salt.length = sizeof(saltdata);
|
||||
|
||||
major = gss_pseudo_random(&minor, ctx, GSS_C_PRF_KEY_FULL,
|
||||
&salt, keysize, &dkey);
|
||||
if (GSS_ERROR(major))
|
||||
return KRB5_PREAUTH_NO_KEY;
|
||||
|
||||
kdkey.keytype = enctype;
|
||||
kdkey.keyvalue.data = dkey.value;
|
||||
kdkey.keyvalue.length = dkey.length;
|
||||
|
||||
ret = krb5_copy_keyblock(context, &kdkey, keyblock);
|
||||
|
||||
_gss_secure_release_buffer(&minor, &dkey);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_gss_pa_unparse_name(krb5_context context,
|
||||
krb5_const_principal principal,
|
||||
gss_name_t *namep)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
char *name = NULL;
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_buffer_desc name_buf;
|
||||
gss_OID name_type;
|
||||
|
||||
*namep = GSS_C_NO_NAME;
|
||||
|
||||
if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
|
||||
if (principal->name.name_string.len != 1)
|
||||
return EINVAL;
|
||||
|
||||
name = principal->name.name_string.val[0];
|
||||
} else {
|
||||
ret = krb5_unparse_name(context, principal, &name);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
name_buf.length = strlen(name);
|
||||
name_buf.value = name;
|
||||
|
||||
if (principal->name.name_type == KRB5_NT_PRINCIPAL ||
|
||||
principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL)
|
||||
name_type = GSS_C_NT_USER_NAME;
|
||||
else
|
||||
name_type = GSS_KRB5_NT_PRINCIPAL_NAME;
|
||||
|
||||
major = gss_import_name(&minor, &name_buf, name_type, namep);
|
||||
|
||||
if (name != principal->name.name_string.val[0])
|
||||
krb5_xfree(name);
|
||||
|
||||
return _krb5_gss_map_error(major, minor);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_gss_pa_parse_name(krb5_context context,
|
||||
gss_const_name_t name,
|
||||
int flags,
|
||||
krb5_principal *principal)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
char *displayed_name0;
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_OID name_type = GSS_C_NO_OID;
|
||||
gss_buffer_desc displayed_name = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
major = gss_display_name(&minor, name, &displayed_name, &name_type);
|
||||
if (GSS_ERROR(major))
|
||||
return _krb5_gss_map_error(major, minor);
|
||||
|
||||
if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) {
|
||||
ret = krb5_make_principal(context, principal, KRB5_ANON_REALM,
|
||||
KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL);
|
||||
if (ret == 0)
|
||||
(*principal)->name.name_type = KRB5_NT_WELLKNOWN;
|
||||
} else {
|
||||
displayed_name0 = malloc(displayed_name.length + 1);
|
||||
if (displayed_name0 == NULL)
|
||||
return krb5_enomem(context);
|
||||
|
||||
memcpy(displayed_name0, displayed_name.value, displayed_name.length);
|
||||
displayed_name0[displayed_name.length] = '\0';
|
||||
|
||||
ret = krb5_parse_name_flags(context, displayed_name0, flags, principal);
|
||||
gss_release_buffer(&minor, &displayed_name);
|
||||
free(displayed_name0);
|
||||
}
|
||||
|
||||
gss_release_buffer(&minor, &displayed_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
_krb5_gss_data_to_buffer(const krb5_data *data, gss_buffer_t buffer)
|
||||
{
|
||||
if (data) {
|
||||
buffer->length = data->length;
|
||||
buffer->value = data->data;
|
||||
} else {
|
||||
_mg_buffer_zero(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_krb5_gss_buffer_to_data(gss_const_buffer_t buffer, krb5_data *data)
|
||||
{
|
||||
if (buffer) {
|
||||
data->length = buffer->length;
|
||||
data->data = buffer->value;
|
||||
} else {
|
||||
krb5_data_zero(data);
|
||||
}
|
||||
}
|
@@ -43,6 +43,7 @@ HEIMDAL_GSS_2.0 {
|
||||
gss_export_name;
|
||||
gss_export_name_composite;
|
||||
gss_export_sec_context;
|
||||
gss_get_instance;
|
||||
gss_get_mic;
|
||||
gss_get_neg_mechs;
|
||||
gss_get_name_attribute;
|
||||
@@ -116,6 +117,7 @@ HEIMDAL_GSS_2.0 {
|
||||
gsskrb5_set_send_to_kdc;
|
||||
gsskrb5_set_time_offset;
|
||||
krb5_gss_register_acceptor_identity;
|
||||
krb5_gss_set_init_creds;
|
||||
gss_display_mech_attr;
|
||||
gss_inquire_attrs_for_mech;
|
||||
gss_indicate_mechs_by_attrs;
|
||||
@@ -133,6 +135,13 @@ HEIMDAL_GSS_2.0 {
|
||||
_gsskrb5cfx_wrap_length_cfx;
|
||||
_gssapi_wrap_size_cfx;
|
||||
|
||||
_krb5_gss_data_to_buffer;
|
||||
_krb5_gss_buffer_to_data;
|
||||
_krb5_gss_map_error;
|
||||
_krb5_gss_pa_parse_name;
|
||||
_krb5_gss_pa_unparse_name;
|
||||
_krb5_gss_pa_derive_key;
|
||||
|
||||
__gss_krb5_copy_ccache_x_oid_desc;
|
||||
__gss_krb5_get_tkt_flags_x_oid_desc;
|
||||
__gss_krb5_extract_authz_data_from_sec_context_x_oid_desc;
|
||||
|
Reference in New Issue
Block a user