diff options
Diffstat (limited to 'lib/gssapi/test_context.c')
-rw-r--r-- | lib/gssapi/test_context.c | 196 |
1 files changed, 180 insertions, 16 deletions
diff --git a/lib/gssapi/test_context.c b/lib/gssapi/test_context.c index 5bdf474d9b93..36a7389aba2f 100644 --- a/lib/gssapi/test_context.c +++ b/lib/gssapi/test_context.c @@ -42,6 +42,7 @@ static char *type_string; static char *mech_string; +static char *mechs_string; static char *ret_mech_string; static char *client_name; static char *client_password; @@ -50,6 +51,7 @@ static int mutual_auth_flag = 0; static int dce_style_flag = 0; static int wrapunwrap_flag = 0; static int iov_flag = 0; +static int aead_flag = 0; static int getverifymic_flag = 0; static int deleg_flag = 0; static int policy_deleg_flag = 0; @@ -90,17 +92,49 @@ init_o2n(void) static gss_OID string_to_oid(const char *name) { - int i; + size_t 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); } +static void +string_to_oids(gss_OID_set *oidsetp, gss_OID_set oidset, + gss_OID_desc *oidarray, size_t oidarray_len, + char *names) +{ + char *name; + char *s; + + if (names[0] == '\0') { + *oidsetp = GSS_C_NO_OID_SET; + return; + } + + oidset->elements = &oidarray[0]; + if (strcasecmp(names, "all") == 0) { + if (sizeof(o2n)/sizeof(o2n[0]) > oidarray_len) + errx(1, "internal error: oidarray must be enlarged"); + for (oidset->count = 0; oidset->count < oidarray_len; oidset->count++) + oidset->elements[oidset->count] = *o2n[oidset->count].oid; + } else { + for (oidset->count = 0, name = strtok_r(names, ", ", &s); + name != NULL; + oidset->count++, name = strtok_r(NULL, ", ", &s)) { + if (oidset->count >= oidarray_len) + errx(1, "too many mech names given"); + oidset->elements[oidset->count] = *string_to_oid(name); + } + oidset->count = oidset->count; + } + *oidsetp = oidset; +} + static const char * oid_to_string(const gss_OID oid) { - int i; + size_t i; for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) if (gss_oid_equal(oid, o2n[i].oid)) return o2n[i].name; @@ -411,11 +445,66 @@ wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) if (conf_state2 != conf_state) errx(1, "conf state wrong for iov: %x", flags); + gss_release_iov_buffer(&min_stat, iov, iov_len); free(token.data); } static void +wrapunwrap_aead(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) +{ + gss_buffer_desc token, assoc, message = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output; + OM_uint32 min_stat, maj_stat; + gss_qop_t qop_state; + int conf_state, conf_state2; + char assoc_data[9] = "ABCheader"; + char token_data[16] = "0123456789abcdef"; + + if (flags & USE_SIGN_ONLY) { + assoc.value = assoc_data; + assoc.length = 9; + } else { + assoc.value = NULL; + assoc.length = 0; + } + + token.value = token_data; + token.length = 16; + + maj_stat = gss_wrap_aead(&min_stat, cctx, dce_style_flag || flags & USE_CONF, + GSS_C_QOP_DEFAULT, &assoc, &token, + &conf_state, &message); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_wrap_aead failed"); + + if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) { + maj_stat = gss_unwrap(&min_stat, sctx, &message, + &output, &conf_state2, &qop_state); + + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap from gss_wrap_aead failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + } else { + maj_stat = gss_unwrap_aead(&min_stat, sctx, &message, &assoc, + &output, &conf_state2, &qop_state); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap_aead failed: %x %s", flags, + gssapi_err(maj_stat, min_stat, mechoid)); + } + + if (output.length != token.length) + errx(1, "plaintext length wrong for aead"); + else if (memcmp(output.value, token.value, token.length) != 0) + errx(1, "plaintext wrong for aead"); + if (conf_state2 != conf_state) + errx(1, "conf state wrong for aead: %x", flags); + + gss_release_buffer(&min_stat, &message); + gss_release_buffer(&min_stat, &output); +} + +static void getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid) { gss_buffer_desc input_token, output_token; @@ -461,7 +550,8 @@ empty_release(void) static struct getargs args[] = { {"name-type",0, arg_string, &type_string, "type of name", NULL }, - {"mech-type",0, arg_string, &mech_string, "type of mech", NULL }, + {"mech-type",0, arg_string, &mech_string, "mech type (name)", NULL }, + {"mech-types",0, arg_string, &mechs_string, "mech types (names)", NULL }, {"ret-mech-type",0, arg_string, &ret_mech_string, "type of return mech", NULL }, {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag, @@ -473,6 +563,7 @@ static struct getargs args[] = { {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL }, {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL }, {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL }, + {"aead", 0, arg_flag, &aead_flag, "wrap/unwrap aead", NULL }, {"getverifymic",0, arg_flag, &getverifymic_flag, "get and verify mic", NULL }, {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL }, @@ -501,7 +592,7 @@ usage (int ret) int main(int argc, char **argv) { - int optind = 0; + int optidx = 0; OM_uint32 min_stat, maj_stat; gss_ctx_id_t cctx, sctx; void *ctx; @@ -509,6 +600,9 @@ main(int argc, char **argv) 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; + gss_OID_desc oids[4]; + gss_OID_set_desc mechoid_descs; + gss_OID_set mechoids = GSS_C_NO_OID_SET; setprogname(argv[0]); @@ -519,7 +613,7 @@ main(int argc, char **argv) cctx = sctx = GSS_C_NO_CONTEXT; - if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)) + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) @@ -530,8 +624,8 @@ main(int argc, char **argv) exit(0); } - argc -= optind; - argv += optind; + argc -= optidx; + argv += optidx; if (argc != 1) usage(1); @@ -546,13 +640,44 @@ main(int argc, char **argv) else if (strcmp(type_string, "krb5-principal-name") == 0) nameoid = GSS_KRB5_NT_PRINCIPAL_NAME; else - errx(1, "%s not suppported", type_string); + errx(1, "%s not supported", type_string); if (mech_string == NULL) mechoid = GSS_KRB5_MECHANISM; else mechoid = string_to_oid(mech_string); + if (mechs_string == NULL) { + /* + * We ought to be able to use the OID set of the one mechanism + * OID given. But there's some breakage that conspires to make + * that fail though it should succeed: + * + * - the NTLM gss_acquire_cred() refuses to work with + * desired_name == GSS_C_NO_NAME + * - gss_acquire_cred() with desired_mechs == GSS_C_NO_OID_SET + * does work here because we happen to have Kerberos + * credentials in check-ntlm, and the subsequent + * gss_init_sec_context() call finds no cred element for NTLM + * but plows on anyways, surprisingly enough, and then the + * NTLM gss_init_sec_context() just works. + * + * In summary, there's some breakage in gss_init_sec_context() + * and some breakage in NTLM that conspires against us here. + * + * We work around this in check-ntlm and check-spnego by adding + * --client-name=user1@${R} to the invocations of this test + * program that require it. + */ + oids[0] = *mechoid; + mechoid_descs.elements = &oids[0]; + mechoid_descs.count = 1; + mechoids = &mechoid_descs; + } else { + string_to_oids(&mechoids, &mechoid_descs, + oids, sizeof(oids)/sizeof(oids[0]), mechs_string); + } + if (gsskrb5_acceptor_identity) { maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity); if (maj_stat) @@ -582,19 +707,24 @@ main(int argc, char **argv) cname, &credential_data, GSS_C_INDEFINITE, - GSS_C_NO_OID_SET, + mechoids, GSS_C_INITIATE, &client_cred, NULL, NULL); - if (GSS_ERROR(maj_stat)) + if (GSS_ERROR(maj_stat)) { + if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1) + mechoid = &mechoids->elements[0]; + else + mechoid = GSS_C_NO_OID; errx(1, "gss_acquire_cred_with_password: %s", - gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + gssapi_err(maj_stat, min_stat, mechoid)); + } } else { maj_stat = gss_acquire_cred(&min_stat, cname, GSS_C_INDEFINITE, - GSS_C_NO_OID_SET, + mechoids, GSS_C_INITIATE, &client_cred, NULL, @@ -644,7 +774,7 @@ main(int argc, char **argv) /* XXX should be actual_mech */ if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) { - time_t time; + time_t sc_time; gss_buffer_desc authz_data; gss_buffer_desc in, out1, out2; krb5_keyblock *keyblock, *keyblock2; @@ -685,15 +815,15 @@ main(int argc, char **argv) maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat, sctx, - &time); + &sc_time); if (maj_stat != GSS_S_COMPLETE) errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s", gssapi_err(maj_stat, min_stat, actual_mech)); - if (time > now) + if (sc_time > now) errx(1, "gsskrb5_extract_authtime_from_sec_context failed: " "time authtime is before now: %ld %ld", - (long)time, (long)now); + (long)sc_time, (long)now); maj_stat = gsskrb5_extract_service_keyblock(&min_stat, sctx, @@ -880,6 +1010,29 @@ main(int argc, char **argv) wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); } + if (aead_flag) { + wrapunwrap_aead(cctx, sctx, 0, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech); + + wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, 0, actual_mech); + wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + } + if (getverifymic_flag) { getverifymic(cctx, sctx, actual_mech); getverifymic(cctx, sctx, actual_mech); @@ -905,6 +1058,13 @@ main(int argc, char **argv) gss_release_cred(&min_stat, &cred2); +#if 0 + /* + * XXX We can't do this. Delegated credentials only work with + * the actual_mech. We could gss_store_cred the delegated + * credentials *then* gss_add/acquire_cred() with SPNEGO, then + * we could try loop() with those credentials. + */ /* try again using SPNEGO */ if (verbose_flag) printf("checking spnego on delegated cred\n"); @@ -915,6 +1075,7 @@ main(int argc, char **argv) gss_delete_sec_context(&min_stat, &sctx, NULL); gss_release_cred(&min_stat, &cred2); +#endif /* check export/import */ if (ei_flag) { @@ -943,6 +1104,8 @@ main(int argc, char **argv) gss_delete_sec_context(&min_stat, &cctx, NULL); gss_delete_sec_context(&min_stat, &sctx, NULL); +#if 0 + /* XXX See above */ /* try again using SPNEGO */ if (verbose_flag) printf("checking SPNEGO on export/imported cred\n"); @@ -953,6 +1116,7 @@ main(int argc, char **argv) gss_delete_sec_context(&min_stat, &cctx, NULL); gss_delete_sec_context(&min_stat, &sctx, NULL); +#endif gss_release_cred(&min_stat, &cred2); |