krb5 commit: Limit use of IAKERB
Greg Hudson
ghudson at mit.edu
Mon Aug 10 13:38:01 EDT 2015
https://github.com/krb5/krb5/commit/608a65570aa868d6e03423b5de3b8f82c0bff60b
commit 608a65570aa868d6e03423b5de3b8f82c0bff60b
Author: Greg Hudson <ghudson at mit.edu>
Date: Fri Jul 31 12:31:25 2015 -0400
Limit use of IAKERB
Add the GSS_C_MA_NOT_DFLT_MECH attribute to IAKERB, and filter out
mechs with that attribute from the SPNEGO and gss_acquire_cred()
default mechanisms.
Add a -iakerb option to gss-server and pass it when performing IAKERB
tests. Also add tests using the wrong password, to verify that
gss_acquire_cred_with_password() fails with the wrong password when
using SPNEGO.
ticket: 8021
src/appl/gss-sample/gss-server.c | 22 ++++++++--
src/appl/gss-sample/t_gss_sample.py | 60 ++++++++++++++++++++----------
src/lib/gssapi/krb5/gssapi_krb5.c | 1 +
src/lib/gssapi/mechglue/g_acquire_cred.c | 5 +-
src/lib/gssapi/spnego/spnego_mech.c | 5 +-
5 files changed, 64 insertions(+), 29 deletions(-)
diff --git a/src/appl/gss-sample/gss-server.c b/src/appl/gss-sample/gss-server.c
index 3c116de..c0d0da3 100644
--- a/src/appl/gss-sample/gss-server.c
+++ b/src/appl/gss-sample/gss-server.c
@@ -98,6 +98,7 @@ int verbose = 0;
* Arguments:
*
* service_name (r) the ASCII service name
+ * mech (r) the desired mechanism (or GSS_C_NO_OID)
* server_creds (w) the GSS-API service credentials
*
* Returns: 0 on success, -1 on failure
@@ -107,15 +108,19 @@ int verbose = 0;
* The service name is imported with gss_import_name, and service
* credentials are acquired with gss_acquire_cred. If either opertion
* fails, an error message is displayed and -1 is returned; otherwise,
- * 0 is returned.
+ * 0 is returned. If mech is given, credentials are acquired for the
+ * specified mechanism.
*/
static int
-server_acquire_creds(char *service_name, gss_cred_id_t *server_creds)
+server_acquire_creds(char *service_name, gss_OID mech,
+ gss_cred_id_t *server_creds)
{
gss_buffer_desc name_buf;
gss_name_t server_name;
OM_uint32 maj_stat, min_stat;
+ gss_OID_set_desc mechlist;
+ gss_OID_set mechs = GSS_C_NO_OID_SET;
name_buf.value = service_name;
name_buf.length = strlen(name_buf.value) + 1;
@@ -126,8 +131,12 @@ server_acquire_creds(char *service_name, gss_cred_id_t *server_creds)
return -1;
}
- maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
- GSS_C_NO_OID_SET, GSS_C_ACCEPT,
+ if (mech != GSS_C_NO_OID) {
+ mechlist.count = 1;
+ mechlist.elements = mech;
+ mechs = &mechlist;
+ }
+ maj_stat = gss_acquire_cred(&min_stat, server_name, 0, mechs, GSS_C_ACCEPT,
server_creds, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE) {
display_status("acquiring credentials", maj_stat, min_stat);
@@ -652,6 +661,7 @@ main(int argc, char **argv)
{
char *service_name;
gss_cred_id_t server_creds;
+ gss_OID mech = GSS_C_NO_OID;
OM_uint32 min_stat;
u_short port = 4444;
int once = 0;
@@ -715,6 +725,8 @@ main(int argc, char **argv)
fprintf(stderr, "failed to register keytab\n");
exit(1);
}
+ } else if (strcmp(*argv, "-iakerb") == 0) {
+ mech = (gss_OID)gss_mech_iakerb;
} else
break;
argc--;
@@ -741,7 +753,7 @@ main(int argc, char **argv)
service_name = *argv;
- if (server_acquire_creds(service_name, &server_creds) < 0)
+ if (server_acquire_creds(service_name, mech, &server_creds) < 0)
return -1;
if (do_inetd) {
diff --git a/src/appl/gss-sample/t_gss_sample.py b/src/appl/gss-sample/t_gss_sample.py
index f6cd18c..964e3ba 100755
--- a/src/appl/gss-sample/t_gss_sample.py
+++ b/src/appl/gss-sample/t_gss_sample.py
@@ -29,18 +29,23 @@ gss_client = os.path.join(appdir, 'gss-client')
gss_server = os.path.join(appdir, 'gss-server')
# Run a gss-server process and a gss-client process, with additional
-# gss-client flags given by options. Verify that gss-client displayed
-# the expected output for a successful negotiation, and that we
-# obtained credentials for the host service.
-def server_client_test(realm, options):
+# gss-client flags given by options and additional gss-server flags
+# given by server_options. Return the output of gss-client.
+def run_client_server(realm, options, server_options, expected_code=0):
portstr = str(realm.server_port())
- server = realm.start_server([gss_server, '-port', portstr, 'host'],
- 'starting...')
- output = realm.run([gss_client, '-port', portstr] + options +
- [hostname, 'host', 'testmsg'])
- if 'Signature verified.' not in output:
- fail('Expected message not seen in gss-client output')
+ server_args = [gss_server, '-port', portstr] + server_options + ['host']
+ server = realm.start_server(server_args, 'starting...')
+ out = realm.run([gss_client, '-port', portstr] + options +
+ [hostname, 'host', 'testmsg'], expected_code=expected_code)
stop_daemon(server)
+ return out
+
+# Run a gss-server and gss-client process, and verify that gss-client
+# displayed the expected output for a successful negotiation.
+def server_client_test(realm, options, server_options):
+ out = run_client_server(realm, options, server_options)
+ if 'Signature verified.' not in out:
+ fail('Expected message not seen in gss-client output')
# Make up a filename to hold user's initial credentials.
def ccache_savefile(realm):
@@ -55,27 +60,37 @@ def ccache_restore(realm):
shutil.copyfile(ccache_savefile(realm), realm.ccache)
# Perform a regular (TGS path) test of the server and client.
-def tgs_test(realm, options):
+def tgs_test(realm, options, server_options=[]):
ccache_restore(realm)
- server_client_test(realm, options)
+ server_client_test(realm, options, server_options)
realm.klist(realm.user_princ, realm.host_princ)
# Perform a test of the server and client with initial credentials
# obtained through gss_acquire_cred_with_password().
-def pw_test(realm, options):
+def pw_test(realm, options, server_options=[]):
if os.path.exists(realm.ccache):
os.remove(realm.ccache)
- server_client_test(realm, options + ['-user', realm.user_princ,
- '-pass', password('user')])
+ options = options + ['-user', realm.user_princ, '-pass', password('user')]
+ server_client_test(realm, options, server_options)
if os.path.exists(realm.ccache):
fail('gss_acquire_cred_with_password created ccache')
+# Perform a test using the wrong password, and make sure that failure
+# occurs during the expected operation (gss_init_sec_context() for
+# IAKERB, gss_aqcuire_cred_with_password() otherwise).
+def wrong_pw_test(realm, options, server_options=[], iakerb=False):
+ options = options + ['-user', realm.user_princ, '-pass', 'wrongpw']
+ out = run_client_server(realm, options, server_options, expected_code=1)
+ failed_op = 'initializing context' if iakerb else 'acquiring creds'
+ if 'GSS-API error ' + failed_op not in out:
+ fail('Expected error not seen in gss-client output')
+
# Perform a test of the server and client with initial credentials
# obtained with the client keytab
-def kt_test(realm, options):
+def kt_test(realm, options, server_options=[]):
if os.path.exists(realm.ccache):
os.remove(realm.ccache)
- server_client_test(realm, options)
+ server_client_test(realm, options, server_options)
realm.klist(realm.user_princ, realm.host_princ)
for realm in multipass_realms():
@@ -83,19 +98,24 @@ for realm in multipass_realms():
tgs_test(realm, ['-krb5'])
tgs_test(realm, ['-spnego'])
- tgs_test(realm, ['-iakerb'])
+ tgs_test(realm, ['-iakerb'], ['-iakerb'])
# test default (i.e., krb5) mechanism with GSS_C_DCE_STYLE
tgs_test(realm, ['-dce'])
pw_test(realm, ['-krb5'])
pw_test(realm, ['-spnego'])
- pw_test(realm, ['-iakerb'])
+ pw_test(realm, ['-iakerb'], ['-iakerb'])
pw_test(realm, ['-dce'])
+ wrong_pw_test(realm, ['-krb5'])
+ wrong_pw_test(realm, ['-spnego'])
+ wrong_pw_test(realm, ['-iakerb'], ['-iakerb'], True)
+ wrong_pw_test(realm, ['-dce'])
+
realm.extract_keytab(realm.user_princ, realm.client_keytab)
kt_test(realm, ['-krb5'])
kt_test(realm, ['-spnego'])
- kt_test(realm, ['-iakerb'])
+ kt_test(realm, ['-iakerb'], ['-iakerb'])
kt_test(realm, ['-dce'])
success('GSS sample application')
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index aa5c403..0be92e4 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -749,6 +749,7 @@ krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
if (g_OID_equal(mech, gss_mech_iakerb)) {
MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
+ MA_SUPPORTED(GSS_C_MA_NOT_DFLT_MECH);
} else if (!g_OID_equal(mech, gss_mech_krb5)) {
MA_SUPPORTED(GSS_C_MA_DEPRECATED);
}
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c
index 22be5b4..ff250de 100644
--- a/src/lib/gssapi/mechglue/g_acquire_cred.c
+++ b/src/lib/gssapi/mechglue/g_acquire_cred.c
@@ -136,7 +136,7 @@ OM_uint32 * time_rec;
OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
gss_OID_set mechs = GSS_C_NO_OID_SET;
gss_OID_set_desc except_attrs;
- gss_OID_desc attr_oids[1];
+ gss_OID_desc attr_oids[2];
unsigned int i;
gss_union_cred_t creds = NULL;
@@ -158,7 +158,8 @@ OM_uint32 * time_rec;
*/
if (desired_mechs == GSS_C_NULL_OID_SET) {
attr_oids[0] = *GSS_C_MA_DEPRECATED;
- except_attrs.count = 1;
+ attr_oids[1] = *GSS_C_MA_NOT_DFLT_MECH;
+ except_attrs.count = 2;
except_attrs.elements = attr_oids;
major = gss_indicate_mechs_by_attrs(minor_status, GSS_C_NO_OID_SET,
&except_attrs, GSS_C_NO_OID_SET,
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 9a794ab..8ade245 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -3013,10 +3013,11 @@ get_available_mechs(OM_uint32 *minor_status,
OM_uint32 major_status = GSS_S_COMPLETE, tmpmin;
gss_OID_set mechs, goodmechs;
gss_OID_set_desc except_attrs;
- gss_OID_desc attr_oids[1];
+ gss_OID_desc attr_oids[2];
attr_oids[0] = *GSS_C_MA_DEPRECATED;
- except_attrs.count = 1;
+ attr_oids[1] = *GSS_C_MA_NOT_DFLT_MECH;
+ except_attrs.count = 2;
except_attrs.elements = attr_oids;
major_status = gss_indicate_mechs_by_attrs(minor_status,
GSS_C_NO_OID_SET,
More information about the cvs-krb5
mailing list