diff options
Diffstat (limited to 'lib/gssapi/test_context.c')
| -rw-r--r-- | lib/gssapi/test_context.c | 586 | 
1 files changed, 507 insertions, 79 deletions
| diff --git a/lib/gssapi/test_context.c b/lib/gssapi/test_context.c index e02535aec22a..5bdf474d9b93 100644 --- a/lib/gssapi/test_context.c +++ b/lib/gssapi/test_context.c @@ -1,18 +1,18 @@  /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden).  - * All rights reserved.  + * Copyright (c) 2006 - 2008 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:  + * 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.  + * 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.  + * 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 KTH nor the names of its contributors may be   *    used to endorse or promote products derived from this software without @@ -34,41 +34,67 @@  #include "krb5/gsskrb5_locl.h"  #include <err.h>  #include <getarg.h> +#include <gssapi.h> +#include <gssapi_krb5.h> +#include <gssapi_spnego.h> +#include <gssapi_ntlm.h>  #include "test_common.h" -RCSID("$Id: test_context.c 20075 2007-01-31 06:05:19Z lha $"); -  static char *type_string;  static char *mech_string;  static char *ret_mech_string; +static char *client_name; +static char *client_password;  static int dns_canon_flag = -1;  static int mutual_auth_flag = 0;  static int dce_style_flag = 0;  static int wrapunwrap_flag = 0; +static int iov_flag = 0;  static int getverifymic_flag = 0;  static int deleg_flag = 0; +static int policy_deleg_flag = 0; +static int server_no_deleg_flag = 0; +static int ei_flag = 0; +static char *gsskrb5_acceptor_identity = NULL; +static char *session_enctype_string = NULL; +static int client_time_offset = 0; +static int server_time_offset = 0; +static int max_loops = 0; +static char *limit_enctype_string = NULL;  static int version_flag = 0;  static int verbose_flag = 0;  static int help_flag	= 0; +static krb5_context context; +static krb5_enctype limit_enctype = 0; +  static struct {      const char *name; -    gss_OID *oid; +    gss_OID oid;  } o2n[] = { -    { "krb5", &GSS_KRB5_MECHANISM }, -    { "spnego", &GSS_SPNEGO_MECHANISM }, -    { "ntlm", &GSS_NTLM_MECHANISM }, -    { "sasl-digest-md5", &GSS_SASL_DIGEST_MD5_MECHANISM } +    { "krb5", NULL /* GSS_KRB5_MECHANISM */ }, +    { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ }, +    { "ntlm", NULL /* GSS_NTLM_MECHANISM */ }, +    { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }  }; +static void +init_o2n(void) +{ +    o2n[0].oid = GSS_KRB5_MECHANISM; +    o2n[1].oid = GSS_SPNEGO_MECHANISM; +    o2n[2].oid = GSS_NTLM_MECHANISM; +    o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM; +} +  static gss_OID  string_to_oid(const char *name)  {      int i;      for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)  	if (strcasecmp(name, o2n[i].name) == 0) -	    return *o2n[i].oid; -    errx(1, "name %s not unknown", name); +	    return o2n[i].oid; +    errx(1, "name '%s' not unknown", name);  }  static const char * @@ -76,7 +102,7 @@ oid_to_string(const gss_OID oid)  {      int i;      for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) -	if (gss_oid_equal(oid, *o2n[i].oid)) +	if (gss_oid_equal(oid, o2n[i].oid))  	    return o2n[i].name;      return "unknown oid";  } @@ -86,16 +112,17 @@ loop(gss_OID mechoid,       gss_OID nameoid, const char *target,       gss_cred_id_t init_cred,       gss_ctx_id_t *sctx, gss_ctx_id_t *cctx, -     gss_OID *actual_mech,  +     gss_OID *actual_mech,       gss_cred_id_t *deleg_cred)  {      int server_done = 0, client_done = 0; +    int num_loops = 0;      OM_uint32 maj_stat, min_stat;      gss_name_t gss_target_name;      gss_buffer_desc input_token, output_token;      OM_uint32 flags = 0, ret_cflags, ret_sflags; -    gss_OID actual_mech_client;  -    gss_OID actual_mech_server;  +    gss_OID actual_mech_client; +    gss_OID actual_mech_server;      *actual_mech = GSS_C_NO_OID; @@ -108,6 +135,8 @@ loop(gss_OID mechoid,  	flags |= GSS_C_DCE_STYLE;      if (deleg_flag)  	flags |= GSS_C_DELEG_FLAG; +    if (policy_deleg_flag) +	flags |= GSS_C_DELEG_POLICY_FLAG;      input_token.value = rk_UNCONST(target);      input_token.length = strlen(target); @@ -123,14 +152,17 @@ loop(gss_OID mechoid,      input_token.value = NULL;      while (!server_done || !client_done) { +	num_loops++; + +	gsskrb5_set_time_offset(client_time_offset);  	maj_stat = gss_init_sec_context(&min_stat,  					init_cred,  					cctx,  					gss_target_name, -					mechoid,  +					mechoid,  					flags, -					0,  +					0,  					NULL,  					&input_token,  					&actual_mech_client, @@ -145,12 +177,16 @@ loop(gss_OID mechoid,  	else  	    client_done = 1; +	gsskrb5_get_time_offset(&client_time_offset); +  	if (client_done && server_done)  	    break;  	if (input_token.length != 0)  	    gss_release_buffer(&min_stat, &input_token); +	gsskrb5_set_time_offset(server_time_offset); +  	maj_stat = gss_accept_sec_context(&min_stat,  					  sctx,  					  GSS_C_NO_CREDENTIAL, @@ -166,8 +202,7 @@ loop(gss_OID mechoid,  		errx(1, "accept_sec_context: %s",  		     gssapi_err(maj_stat, min_stat, actual_mech_server)); -	if (verbose_flag) -	    printf("%.*s", (int)input_token.length, (char *)input_token.value); +	gsskrb5_get_time_offset(&server_time_offset);  	if (output_token.length != 0)  	    gss_release_buffer(&min_stat, &output_token); @@ -176,24 +211,42 @@ loop(gss_OID mechoid,  	    ;  	else  	    server_done = 1; -    }	 +    }      if (output_token.length != 0)  	gss_release_buffer(&min_stat, &output_token);      if (input_token.length != 0)  	gss_release_buffer(&min_stat, &input_token);      gss_release_name(&min_stat, &gss_target_name); +    if (deleg_flag || policy_deleg_flag) { +	if (server_no_deleg_flag) { +	    if (*deleg_cred != GSS_C_NO_CREDENTIAL) +		errx(1, "got delegated cred but didn't expect one"); +	} else if (*deleg_cred == GSS_C_NO_CREDENTIAL) +	    errx(1, "asked for delegarated cred but did get one"); +    } else if (*deleg_cred != GSS_C_NO_CREDENTIAL) +	  errx(1, "got deleg_cred cred but didn't ask"); +      if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)  	errx(1, "mech mismatch");      *actual_mech = actual_mech_server; + +    if (max_loops && num_loops > max_loops) +	errx(1, "num loops %d was lager then max loops %d", +	     num_loops, max_loops); + +    if (verbose_flag) { +	printf("server time offset: %d\n", server_time_offset); +	printf("client time offset: %d\n", client_time_offset); +	printf("num loops %d\n", num_loops); +    }  }  static void -wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid) +wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)  {      gss_buffer_desc input_token, output_token, output_token2;      OM_uint32 min_stat, maj_stat; -    int32_t flags = 0;      gss_qop_t qop_state;      int conf_state; @@ -211,6 +264,155 @@ wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)      if (maj_stat != GSS_S_COMPLETE)  	errx(1, "gss_unwrap failed: %s",  	     gssapi_err(maj_stat, min_stat, mechoid)); + +    gss_release_buffer(&min_stat, &output_token); +    gss_release_buffer(&min_stat, &output_token2); + +#if 0 /* doesn't work for NTLM yet */ +    if (!!conf_state != !!flags) +	errx(1, "conf_state mismatch"); +#endif +} + +#define USE_CONF		1 +#define USE_HEADER_ONLY		2 +#define USE_SIGN_ONLY		4 +#define FORCE_IOV		8 + +static void +wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) +{ +    krb5_data token, header, trailer; +    OM_uint32 min_stat, maj_stat; +    gss_qop_t qop_state; +    int conf_state, conf_state2; +    gss_iov_buffer_desc iov[6]; +    unsigned char *p; +    int iov_len; +    char header_data[9] = "ABCheader"; +    char trailer_data[10] = "trailerXYZ"; + +    char token_data[16] = "0123456789abcdef"; + +    memset(&iov, 0, sizeof(iov)); + +    if (flags & USE_SIGN_ONLY) { +	header.data = header_data; +	header.length = 9; +	trailer.data = trailer_data; +	trailer.length = 10; +    } else { +	header.data = NULL; +	header.length = 0; +	trailer.data = NULL; +	trailer.length = 0; +    } + +    token.data = token_data; +    token.length = 16; + +    iov_len = sizeof(iov)/sizeof(iov[0]); + +    memset(iov, 0, sizeof(iov)); + +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; + +    if (header.length != 0) { +	iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; +	iov[1].buffer.length = header.length; +	iov[1].buffer.value = header.data; +    } else { +	iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY; +	iov[1].buffer.length = 0; +	iov[1].buffer.value = NULL; +    } +    iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; +    iov[2].buffer.length = token.length; +    iov[2].buffer.value = token.data; +    if (trailer.length != 0) { +	iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; +	iov[3].buffer.length = trailer.length; +	iov[3].buffer.value = trailer.data; +    } else { +	iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY; +	iov[3].buffer.length = 0; +	iov[3].buffer.value = NULL; +    } +    if (dce_style_flag) { +	iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY; +    } else { +	iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; +    } +    iov[4].buffer.length = 0; +    iov[4].buffer.value = 0; +    if (dce_style_flag) { +	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY; +    } else if (flags & USE_HEADER_ONLY) { +	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY; +    } else { +	iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; +    } +    iov[5].buffer.length = 0; +    iov[5].buffer.value = 0; + +    maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state, +			    iov, iov_len); +    if (maj_stat != GSS_S_COMPLETE) +	errx(1, "gss_wrap_iov failed"); + +    token.length = +	iov[0].buffer.length + +	iov[1].buffer.length + +	iov[2].buffer.length + +	iov[3].buffer.length + +	iov[4].buffer.length + +	iov[5].buffer.length; +    token.data = emalloc(token.length); + +    p = token.data; +    memcpy(p, iov[0].buffer.value, iov[0].buffer.length); +    p += iov[0].buffer.length; +    memcpy(p, iov[1].buffer.value, iov[1].buffer.length); +    p += iov[1].buffer.length; +    memcpy(p, iov[2].buffer.value, iov[2].buffer.length); +    p += iov[2].buffer.length; +    memcpy(p, iov[3].buffer.value, iov[3].buffer.length); +    p += iov[3].buffer.length; +    memcpy(p, iov[4].buffer.value, iov[4].buffer.length); +    p += iov[4].buffer.length; +    memcpy(p, iov[5].buffer.value, iov[5].buffer.length); +    p += iov[5].buffer.length; + +    assert(p - ((unsigned char *)token.data) == token.length); + +    if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) { +	gss_buffer_desc input, output; + +	input.value = token.data; +	input.length = token.length; + +	maj_stat = gss_unwrap(&min_stat, sctx, &input, +			      &output, &conf_state2, &qop_state); + +	if (maj_stat != GSS_S_COMPLETE) +	    errx(1, "gss_unwrap from gss_wrap_iov failed: %s", +		 gssapi_err(maj_stat, min_stat, mechoid)); + +	gss_release_buffer(&min_stat, &output); +    } else { +	maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state, +				  iov, iov_len); + +	if (maj_stat != GSS_S_COMPLETE) +	    errx(1, "gss_unwrap_iov failed: %x %s", flags, +		 gssapi_err(maj_stat, min_stat, mechoid)); + +    } +    if (conf_state2 != conf_state) +	errx(1, "conf state wrong for iov: %x", flags); + + +    free(token.data);  }  static void @@ -234,8 +436,24 @@ getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)      if (maj_stat != GSS_S_COMPLETE)  	errx(1, "gss_verify_mic failed: %s",  	     gssapi_err(maj_stat, min_stat, mechoid)); + +    gss_release_buffer(&min_stat, &output_token);  } +static void +empty_release(void) +{ +    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; +    gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; +    gss_name_t name = GSS_C_NO_NAME; +    gss_OID_set oidset = GSS_C_NO_OID_SET; +    OM_uint32 junk; + +    gss_delete_sec_context(&junk, &ctx, NULL); +    gss_release_cred(&junk, &cred); +    gss_release_name(&junk, &name); +    gss_release_oid_set(&junk, &oidset); +}  /*   * @@ -246,14 +464,27 @@ static struct getargs args[] = {      {"mech-type",0,	arg_string, &mech_string,  "type of mech", NULL },      {"ret-mech-type",0,	arg_string, &ret_mech_string,       "type of return mech", NULL }, -    {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,  +    {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,       "use dns to canonicalize", NULL },      {"mutual-auth",0,	arg_flag,	&mutual_auth_flag,"mutual auth", NULL }, +    {"client-name", 0,  arg_string,     &client_name, "client name", NULL }, +    {"client-password", 0,  arg_string, &client_password, "client password", NULL }, +    {"limit-enctype",0,	arg_string,	&limit_enctype_string, "enctype", NULL },      {"dce-style",0,	arg_flag,	&dce_style_flag, "dce-style", NULL },      {"wrapunwrap",0,	arg_flag,	&wrapunwrap_flag, "wrap/unwrap", NULL }, -    {"getverifymic",0,	arg_flag,	&getverifymic_flag,  +    {"iov", 0, 		arg_flag,	&iov_flag, "wrap/unwrap iov", NULL }, +    {"getverifymic",0,	arg_flag,	&getverifymic_flag,       "get and verify mic", NULL },      {"delegate",0,	arg_flag,	&deleg_flag, "delegate credential", NULL }, +    {"policy-delegate",0,	arg_flag,	&policy_deleg_flag, "policy delegate credential", NULL }, +    {"server-no-delegate",0,	arg_flag,	&server_no_deleg_flag, +     "server should get a credential", NULL }, +    {"export-import-cred",0,	arg_flag,	&ei_flag, "test export/import cred", NULL }, +    {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL }, +    {"session-enctype",	0, arg_string,	&session_enctype_string, "enctype", NULL }, +    {"client-time-offset",	0, arg_integer,	&client_time_offset, "time", NULL }, +    {"server-time-offset",	0, arg_integer,	&server_time_offset, "time", NULL }, +    {"max-loops",	0, arg_integer,	&max_loops, "time", NULL },      {"version",	0,	arg_flag,	&version_flag, "print version", NULL },      {"verbose",	'v',	arg_flag,	&verbose_flag, "verbose", NULL },      {"help",	0,	arg_flag,	&help_flag,  NULL, NULL } @@ -274,16 +505,23 @@ main(int argc, char **argv)      OM_uint32 min_stat, maj_stat;      gss_ctx_id_t cctx, sctx;      void *ctx; -    gss_OID nameoid, mechoid, actual_mech; -    gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL; +    gss_OID nameoid, mechoid, actual_mech, actual_mech2; +    gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL; +    gss_name_t cname = GSS_C_NO_NAME; +    gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;      setprogname(argv[0]); +    init_o2n(); + +    if (krb5_init_context(&context)) +	errx(1, "krb5_init_context"); +      cctx = sctx = GSS_C_NO_CONTEXT;      if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))  	usage(1); -     +      if (help_flag)  	usage (0); @@ -312,12 +550,85 @@ main(int argc, char **argv)      if (mech_string == NULL)  	mechoid = GSS_KRB5_MECHANISM; -    else  +    else  	mechoid = string_to_oid(mech_string); -    loop(mechoid, nameoid, argv[0], GSS_C_NO_CREDENTIAL, +    if (gsskrb5_acceptor_identity) { +	maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity); +	if (maj_stat) +	    errx(1, "gsskrb5_acceptor_identity: %s", +		 gssapi_err(maj_stat, 0, GSS_C_NO_OID)); +    } + +    if (client_password) { +	credential_data.value = client_password; +	credential_data.length = strlen(client_password); +    } + +    if (client_name) { +	gss_buffer_desc cn; + +	cn.value = client_name; +	cn.length = strlen(client_name); + +	maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname); +	if (maj_stat) +	    errx(1, "gss_import_name: %s", +		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); +    } + +    if (client_password) { +	maj_stat = gss_acquire_cred_with_password(&min_stat, +						  cname, +						  &credential_data, +						  GSS_C_INDEFINITE, +						  GSS_C_NO_OID_SET, +						  GSS_C_INITIATE, +						  &client_cred, +						  NULL, +						  NULL); +	if (GSS_ERROR(maj_stat)) +	    errx(1, "gss_acquire_cred_with_password: %s", +		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); +    } else { +	maj_stat = gss_acquire_cred(&min_stat, +				    cname, +				    GSS_C_INDEFINITE, +				    GSS_C_NO_OID_SET, +				    GSS_C_INITIATE, +				    &client_cred, +				    NULL, +				    NULL); +	if (GSS_ERROR(maj_stat)) +	    errx(1, "gss_acquire_cred: %s", +		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); +    } + +    if (limit_enctype_string) { +	krb5_error_code ret; + +	ret = krb5_string_to_enctype(context, +				     limit_enctype_string, +				     &limit_enctype); +	if (ret) +	    krb5_err(context, 1, ret, "krb5_string_to_enctype"); +    } + + +    if (limit_enctype) { +	if (client_cred == NULL) +	    errx(1, "client_cred missing"); + +	maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred, +						   1, &limit_enctype); +	if (maj_stat) +	    errx(1, "gss_krb5_set_allowable_enctypes: %s", +		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); +    } + +    loop(mechoid, nameoid, argv[0], client_cred,  	 &sctx, &cctx, &actual_mech, &deleg_cred); -     +      if (verbose_flag)  	printf("resulting mech: %s\n", oid_to_string(actual_mech)); @@ -327,43 +638,38 @@ main(int argc, char **argv)  	retoid = string_to_oid(ret_mech_string);  	if (gss_oid_equal(retoid, actual_mech) == 0) -	    errx(1, "actual_mech mech is not the expected type %s",  +	    errx(1, "actual_mech mech is not the expected type %s",  		 ret_mech_string);      }      /* XXX should be actual_mech */ -    if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {  -	krb5_context context; -	time_t time, skew; +    if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) { +	time_t time;  	gss_buffer_desc authz_data;  	gss_buffer_desc in, out1, out2;  	krb5_keyblock *keyblock, *keyblock2;  	krb5_timestamp now;  	krb5_error_code ret; -	ret = krb5_init_context(&context); +	ret = krb5_timeofday(context, &now);  	if (ret) -	    errx(1, "krb5_init_context"); +	    errx(1, "krb5_timeofday failed"); -	ret = krb5_timeofday(context, &now); -	if (ret)  -		errx(1, "krb5_timeofday failed"); -	  	/* client */  	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,  						     &cctx,  						     1, /* version */  						     &ctx);  	if (maj_stat != GSS_S_COMPLETE) -		errx(1, "gss_krb5_export_lucid_sec_context failed: %s", -		     gssapi_err(maj_stat, min_stat, actual_mech)); -	 -	 +	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s", +		 gssapi_err(maj_stat, min_stat, actual_mech)); + +  	maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);  	if (maj_stat != GSS_S_COMPLETE)  	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",  		     gssapi_err(maj_stat, min_stat, actual_mech)); -	 +  	/* server */  	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,  						     &sctx, @@ -384,13 +690,10 @@ main(int argc, char **argv)  	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",  		     gssapi_err(maj_stat, min_stat, actual_mech)); -	skew = abs(time - now); -	if (skew > krb5_get_max_time_skew(context)) { +	if (time > now)  	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: " -		 "time skew too great %llu > %llu",  -		 (unsigned long long)skew,  -		 (unsigned long long)krb5_get_max_time_skew(context)); -	} +		 "time authtime is before now: %ld %ld", +		 (long)time, (long)now);   	maj_stat = gsskrb5_extract_service_keyblock(&min_stat,  						    sctx, @@ -404,24 +707,28 @@ main(int argc, char **argv)   	maj_stat = gsskrb5_get_subkey(&min_stat,  				      sctx,  				      &keyblock); -	if (maj_stat != GSS_S_COMPLETE  +	if (maj_stat != GSS_S_COMPLETE  	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))  	    errx(1, "gsskrb5_get_subkey server failed: %s",  		     gssapi_err(maj_stat, min_stat, actual_mech));  	if (maj_stat != GSS_S_COMPLETE)  	    keyblock = NULL; -	 +	else if (limit_enctype && keyblock->keytype != limit_enctype) +	    errx(1, "gsskrb5_get_subkey wrong enctype"); +   	maj_stat = gsskrb5_get_subkey(&min_stat,  				      cctx,  				      &keyblock2); -	if (maj_stat != GSS_S_COMPLETE  +	if (maj_stat != GSS_S_COMPLETE  	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))  	    errx(1, "gsskrb5_get_subkey client failed: %s",  		     gssapi_err(maj_stat, min_stat, actual_mech));  	if (maj_stat != GSS_S_COMPLETE)  	    keyblock2 = NULL; +	else if (limit_enctype && keyblock->keytype != limit_enctype) +	    errx(1, "gsskrb5_get_subkey wrong enctype");  	if (keyblock || keyblock2) {  	    if (keyblock == NULL) @@ -433,11 +740,26 @@ main(int argc, char **argv)  		errx(1, "enctype mismatch");  	    if (keyblock->keyvalue.length != keyblock2->keyvalue.length)  		errx(1, "key length mismatch"); -	    if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,  +	    if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,  		       keyblock2->keyvalue.length) != 0)  		errx(1, "key data mismatch");  	} +	if (session_enctype_string) { +	    krb5_enctype enctype; + +	    ret = krb5_string_to_enctype(context, +					 session_enctype_string, +					 &enctype); + +	    if (ret) +		krb5_err(context, 1, ret, "krb5_string_to_enctype"); + +	    if (enctype != keyblock->keytype) +		errx(1, "keytype is not the expected %d != %d", +		     (int)enctype, (int)keyblock2->keytype); +	} +  	if (keyblock)  	    krb5_free_keyblock(context, keyblock);  	if (keyblock2) @@ -446,13 +768,17 @@ main(int argc, char **argv)   	maj_stat = gsskrb5_get_initiator_subkey(&min_stat,  						sctx,  						&keyblock); -	if (maj_stat != GSS_S_COMPLETE  +	if (maj_stat != GSS_S_COMPLETE  	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))  	    errx(1, "gsskrb5_get_initiator_subkey failed: %s",  		     gssapi_err(maj_stat, min_stat, actual_mech)); -	if (maj_stat == GSS_S_COMPLETE) +	if (maj_stat == GSS_S_COMPLETE) { + +	    if (limit_enctype && keyblock->keytype != limit_enctype) +		errx(1, "gsskrb5_get_initiator_subkey wrong enctype");  	    krb5_free_keyblock(context, keyblock); +	}   	maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,  							       sctx, @@ -461,8 +787,6 @@ main(int argc, char **argv)  	if (maj_stat == GSS_S_COMPLETE)  	    gss_release_buffer(&min_stat, &authz_data); -	krb5_free_context(context); -  	memset(&out1, 0, sizeof(out1));  	memset(&out2, 0, sizeof(out2)); @@ -470,19 +794,19 @@ main(int argc, char **argv)  	in.value = "foo";  	in.length = 3; -	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,  +	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,  			  100, &out1); -	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,  +	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,  			  100, &out2);  	if (out1.length != out2.length)  	    errx(1, "prf len mismatch");  	if (memcmp(out1.value, out2.value, out1.length) != 0)  	    errx(1, "prf data mismatch"); -	 +  	gss_release_buffer(&min_stat, &out1); -	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,  +	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,  			  100, &out1);  	if (out1.length != out2.length) @@ -496,9 +820,9 @@ main(int argc, char **argv)  	in.value = "bar";  	in.length = 3; -	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,  +	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,  			  100, &out1); -	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,  +	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,  			  100, &out2);  	if (out1.length != out2.length) @@ -514,11 +838,48 @@ main(int argc, char **argv)      }      if (wrapunwrap_flag) { -	wrapunwrap(cctx, sctx, actual_mech); -	wrapunwrap(cctx, sctx, actual_mech); -	wrapunwrap(sctx, cctx, actual_mech); -	wrapunwrap(sctx, cctx, actual_mech); +	wrapunwrap(cctx, sctx, 0, actual_mech); +	wrapunwrap(cctx, sctx, 1, actual_mech); +	wrapunwrap(sctx, cctx, 0, actual_mech); +	wrapunwrap(sctx, cctx, 1, actual_mech);      } + +    if (iov_flag) { +	wrapunwrap_iov(cctx, sctx, 0, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech); + +	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + +	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + +/* works */ +	wrapunwrap_iov(cctx, sctx, 0, actual_mech); +	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech); + +	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + +	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + +	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech); + +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech); +	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); +    } +      if (getverifymic_flag) {  	getverifymic(cctx, sctx, actual_mech);  	getverifymic(cctx, sctx, actual_mech); @@ -526,17 +887,84 @@ main(int argc, char **argv)  	getverifymic(sctx, cctx, actual_mech);      } +      gss_delete_sec_context(&min_stat, &cctx, NULL);      gss_delete_sec_context(&min_stat, &sctx, NULL);      if (deleg_cred != GSS_C_NO_CREDENTIAL) { +	gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL; +	gss_buffer_desc cb; + +	if (verbose_flag) +	    printf("checking actual mech (%s) on delegated cred\n", +		   oid_to_string(actual_mech)); +	loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2); + +	gss_delete_sec_context(&min_stat, &cctx, NULL); +	gss_delete_sec_context(&min_stat, &sctx, NULL); -	loop(mechoid, nameoid, argv[0], deleg_cred, &cctx, &sctx, &actual_mech, NULL); +	gss_release_cred(&min_stat, &cred2); + +	/* try again using SPNEGO */ +	if (verbose_flag) +	    printf("checking spnego on delegated cred\n"); +	loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx, +	     &actual_mech2, &cred2);  	gss_delete_sec_context(&min_stat, &cctx, NULL);  	gss_delete_sec_context(&min_stat, &sctx, NULL); +	gss_release_cred(&min_stat, &cred2); + +	/* check export/import */ +	if (ei_flag) { + +	    maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb); +	    if (maj_stat != GSS_S_COMPLETE) +		errx(1, "export failed: %s", +		     gssapi_err(maj_stat, min_stat, NULL)); + +	    maj_stat = gss_import_cred(&min_stat, &cb, &cred2); +	    if (maj_stat != GSS_S_COMPLETE) +		errx(1, "import failed: %s", +		     gssapi_err(maj_stat, min_stat, NULL)); + +	    gss_release_buffer(&min_stat, &cb); +	    gss_release_cred(&min_stat, &deleg_cred); + +	    if (verbose_flag) +		printf("checking actual mech (%s) on export/imported cred\n", +		       oid_to_string(actual_mech)); +	    loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx, +		 &actual_mech2, &deleg_cred); + +	    gss_release_cred(&min_stat, &deleg_cred); + +	    gss_delete_sec_context(&min_stat, &cctx, NULL); +	    gss_delete_sec_context(&min_stat, &sctx, NULL); + +	    /* try again using SPNEGO */ +	    if (verbose_flag) +		printf("checking SPNEGO on export/imported cred\n"); +	    loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx, +		 &actual_mech2, &deleg_cred); + +	    gss_release_cred(&min_stat, &deleg_cred); + +	    gss_delete_sec_context(&min_stat, &cctx, NULL); +	    gss_delete_sec_context(&min_stat, &sctx, NULL); + +	    gss_release_cred(&min_stat, &cred2); + +	} else  { +	    gss_release_cred(&min_stat, &deleg_cred); +	} +      } +    empty_release(); + +    krb5_free_context(context); +      return 0;  } | 
