diff options
Diffstat (limited to 'src/util/gss-kernel-lib/t_kgss_kernel.c')
-rw-r--r-- | src/util/gss-kernel-lib/t_kgss_kernel.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/src/util/gss-kernel-lib/t_kgss_kernel.c b/src/util/gss-kernel-lib/t_kgss_kernel.c new file mode 100644 index 0000000000..0d70f1f386 --- /dev/null +++ b/src/util/gss-kernel-lib/t_kgss_kernel.c @@ -0,0 +1,284 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* util/gss-kernel-lib/t_kgss_kernel.c - Kernel portion of test program */ +/* + * Copyright (C) 2011 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * This program links against libkgss.a and is run as a child process of + * t_kgss_user. It receives an exported acceptor context from its parent and + * then exchanges wrap, MIC, and IOV tokens with the parent. + */ + +#include "k5-int.h" +#include <unistd.h> +#include "gssapi_krb5.h" + +/* If major represents an error, display an error message and exit. */ +static void +check(OM_uint32 major, OM_uint32 minor, const char *fn) +{ + if (!GSS_ERROR(major)) + return; + fprintf(stderr, "t_kgss_kernel: %s: major %u, minor %u\n", fn, major, + minor); + /* libkgss doesn't have gss_display_status. */ + exit(1); +} + +#define READ(p, f) (memcpy(&f, p, sizeof(f)), p += sizeof(f)) + +/* Read fields from p into lkey and return the updated pointer. */ +static const unsigned char * +read_lucid_key(const unsigned char *p, gss_krb5_lucid_key_t *lkey) +{ + READ(p, lkey->type); + READ(p, lkey->length); + lkey->data = malloc(lkey->length); + assert(lkey->data != NULL); + memcpy(lkey->data, p, lkey->length); + return p + lkey->length; +} + +/* Read a data packet from stdin, unmarshal it into a lucid context, and import + * the lucid context into a GSS-krb5 acceptor context. */ +static void +read_lucid_context(gss_ctx_id_t *ctx_out) +{ + void *data; + size_t len; + const unsigned char *p; + gss_krb5_lucid_context_v1_t lctx; + OM_uint32 major, minor; + + /* No length checking; totally unsafe outside of this test program. */ + read_data(STDIN_FILENO, &data, &len); + p = data; + READ(p, lctx.version); + READ(p, lctx.initiate); + READ(p, lctx.endtime); + READ(p, lctx.send_seq); + READ(p, lctx.recv_seq); + READ(p, lctx.protocol); + if (lctx.protocol == 0) { + READ(p, lctx.rfc1964_kd.sign_alg); + READ(p, lctx.rfc1964_kd.seal_alg); + p = read_lucid_key(p, &lctx.rfc1964_kd.ctx_key); + } else if (lctx.protocol == 1) { + READ(p, lctx.cfx_kd.have_acceptor_subkey); + p = read_lucid_key(p, &lctx.cfx_kd.ctx_key); + if (lctx.cfx_kd.have_acceptor_subkey) + p = read_lucid_key(p, &lctx.cfx_kd.acceptor_subkey); + } else + abort(); + + major = krb5_gss_import_lucid_sec_context(&minor, &lctx, ctx_out); + check(major, minor, "krb5_gss_import_lucid_sec_context"); +} + +/* Read a wrap token from stdin and verify that it says "userwrap". */ +static void +read_wrap_token(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + unsigned char *data; + size_t len; + gss_buffer_desc wrapped, buf; + + read_data(STDIN_FILENO, &wrapped.value, &wrapped.length); + major = krb5_gss_unwrap(&minor, ctx, &wrapped, &buf, NULL, NULL); + check(major, minor, "krb5_gss_unwrap"); + assert(buf.length == 8 && memcmp(buf.value, "userwrap", 8) == 0); + free(buf.value); + free(wrapped.value); +} + +/* Read a MIC token from stdin and verify that it is for "usermic". */ +static void +read_mic_token(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + unsigned char *data; + size_t len; + gss_buffer_desc mic, buf; + + read_data(STDIN_FILENO, &mic.value, &mic.length); + buf.value = "usermic"; + buf.length = 7; + major = krb5_gss_verify_mic(&minor, ctx, &buf, &mic, NULL); + check(major, minor, "krb5_gss_verify_mic"); + free(mic.value); +} + +/* Read an IOV token from stdin and verify that it is for "userwrapmic" with + * only the "wrap" part wrapped. */ +static void +read_iov_token(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + gss_iov_buffer_desc iov[6]; + + /* Read in buffers and lay out the IOVs. */ + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + read_data(STDIN_FILENO, &iov[0].buffer.value, &iov[0].buffer.length); + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[1].buffer.value = "user"; + iov[1].buffer.length = 4; + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; + read_data(STDIN_FILENO, &iov[2].buffer.value, &iov[2].buffer.length); + iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[3].buffer.value = "mic"; + iov[3].buffer.length = 3; + iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING; + read_data(STDIN_FILENO, &iov[4].buffer.value, &iov[4].buffer.length); + iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER; + read_data(STDIN_FILENO, &iov[5].buffer.value, &iov[5].buffer.length); + + /* Unwrap and check the data contents. */ + major = krb5_gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 6); + check(major, minor, "gss_unwrap_iov"); + assert(iov[2].buffer.length == 4); + assert(memcmp(iov[2].buffer.value, "wrap", 4) == 0); + + free(iov[0].buffer.value); + free(iov[2].buffer.value); + free(iov[4].buffer.value); + free(iov[5].buffer.value); +} + +/* Create a wrap token for the text "kernelwrap" and send it to stdout. */ +static void +send_wrap_token(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + gss_buffer_desc buf, wrapped; + + buf.value = "kernelwrap"; + buf.length = 10; + major = krb5_gss_wrap(&minor, ctx, 1, GSS_C_QOP_DEFAULT, &buf, NULL, + &wrapped); + check(major, minor, "krb5_gss_wrap"); + send_data(STDOUT_FILENO, wrapped.value, wrapped.length); + free(wrapped.value); +} + +/* Create a wrap token for the text "kernelmic" and send it to stdout. */ +static void +send_mic_token(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + gss_buffer_desc buf, mic; + + buf.value = "kernelmic"; + buf.length = 9; + major = krb5_gss_get_mic(&minor, ctx, GSS_C_QOP_DEFAULT, &buf, &mic); + check(major, minor, "krb5_gss_get_mic"); + send_data(STDOUT_FILENO, mic.value, mic.length); + free(mic.value); +} + +/* Create an IOV token for "kernelwrapmic", wrapping only the "wrap" part, and + * send the header/data/padding/trailer buffers to stdout. */ +static void +send_iov_token(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + gss_iov_buffer_desc iov[6]; + char *buf, *p; + + /* Lay out skeleton IOVs and compute header, padding, trailer lengths. */ + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.value = NULL; + iov[0].buffer.length = 0; + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[1].buffer.value = "kernel"; + iov[1].buffer.length = 6; + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[2].buffer.value = "wrap"; + iov[2].buffer.length = 4; + iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[3].buffer.value = "mic"; + iov[3].buffer.length = 3; + iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING; + iov[4].buffer.value = NULL; + iov[4].buffer.length = 0; + iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER; + iov[5].buffer.value = NULL; + iov[5].buffer.length = 0; + major = krb5_gss_wrap_iov_length(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL, + iov, 6); + check(major, minor, "krb5_gss_wrap_iov_length"); + + /* Create a payload and set header/data/padding/trailer IOV pointers. */ + buf = malloc(iov[0].buffer.length + iov[2].buffer.length + + iov[4].buffer.length + iov[5].buffer.length); + assert(buf != NULL); + p = buf; + iov[0].buffer.value = p; + p += iov[0].buffer.length; + memcpy(p, "wrap", 4); + iov[2].buffer.value = p; + p += iov[2].buffer.length; + iov[4].buffer.value = p; + p += iov[4].buffer.length; + iov[5].buffer.value = p; + + /* Wrap the payload and send it to fd in chunks. */ + major = krb5_gss_wrap_iov(&minor, ctx, 1, GSS_C_QOP_DEFAULT, NULL, iov, 6); + check(major, minor, "gss_wrap_iov"); + send_data(STDOUT_FILENO, iov[0].buffer.value, iov[0].buffer.length); + send_data(STDOUT_FILENO, iov[2].buffer.value, iov[2].buffer.length); + send_data(STDOUT_FILENO, iov[4].buffer.value, iov[4].buffer.length); + send_data(STDOUT_FILENO, iov[5].buffer.value, iov[5].buffer.length); + free(buf); +} + +/* Delete the krb5 security context ctx. */ +static void +cleanup_context(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + + major = krb5_gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER); + check(major, minor, "gss_delete_sec_context"); +} + +int +main(int argc, char **argv) +{ + gss_ctx_id_t acceptor; + int dummy; + + /* Make the PRNG work since we're not using krb5_init_context. */ + krb5_c_random_os_entropy(NULL, 0, &dummy); + + read_lucid_context(&acceptor); + read_wrap_token(acceptor); + read_mic_token(acceptor); + read_iov_token(acceptor); + send_wrap_token(acceptor); + send_mic_token(acceptor); + send_iov_token(acceptor); + cleanup_context(acceptor); + return 0; +} |