summaryrefslogtreecommitdiffstats
path: root/krb5-1.12-CVE-2014-4341_4342-tests.patch
diff options
context:
space:
mode:
Diffstat (limited to 'krb5-1.12-CVE-2014-4341_4342-tests.patch')
-rw-r--r--krb5-1.12-CVE-2014-4341_4342-tests.patch547
1 files changed, 547 insertions, 0 deletions
diff --git a/krb5-1.12-CVE-2014-4341_4342-tests.patch b/krb5-1.12-CVE-2014-4341_4342-tests.patch
new file mode 100644
index 0000000..9db28e7
--- /dev/null
+++ b/krb5-1.12-CVE-2014-4341_4342-tests.patch
@@ -0,0 +1,547 @@
+Changes to .gitignore removed, chunks for tests/gssapi/Makefile.in adjusted to
+account for t_prf not being around yet, calls to gssint_g__seqstate_init()
+changed to calls to gssint_g_order_init(), changed attempt to export
+gssint_g_seqstate_init() to export gssint_g_order_init().
+
+commit 7a9990d73537dcdd95bf9b280ebfd560adf8342d
+Author: Greg Hudson <ghudson@mit.edu>
+Date: Thu Jun 19 13:13:33 2014 -0400
+
+ Add tests for invalid GSSAPI per-message tokens
+
+ ticket: 7949
+
+--- a/src/lib/gssapi/libgssapi_krb5.exports
++++ b/src/lib/gssapi/libgssapi_krb5.exports
+@@ -157,3 +157,4 @@ gss_inquire_name
+ gss_acquire_cred_from
+ gss_add_cred_from
+ gss_store_cred_into
++gssint_g_order_init
+diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
+index ac6a435..5effd90 100644
+--- a/src/tests/gssapi/Makefile.in
++++ b/src/tests/gssapi/Makefile.in
+@@ -1,6 +1,7 @@
+ mydir=tests$(S)gssapi
+ BUILDTOP=$(REL)..$(S)..
+ DEFINES = -DUSE_AUTOCONF_H
++LOCALINCLUDES = -I../../lib/gssapi/mechglue -I../../lib/gssapi/generic -I../../lib/gssapi/krb5
+
+ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
+ $(srcdir)/t_accname.c $(srcdir)/t_ccselect.c $(srcdir)/t_credstore.c \
+@@ -12,27 +13,28 @@ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
+ $(srcdir)/t_accname.c $(srcdir)/t_ccselect.c $(srcdir)/t_credstore.c \
+ $(srcdir)/t_enctypes.c $(srcdir)/t_err.c $(srcdir)/t_export_cred.c \
+ $(srcdir)/t_export_name.c $(srcdir)/t_gssexts.c \
+- $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c $(srcdir)/t_inq_cred.c \
+- $(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
++ $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c $(srcdir)/t_invalid.c \
++ $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
+ $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c $(srcdir)/t_s4u.c \
+ $(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
+ $(srcdir)/t_spnego.c
+
+ OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_ccselect.o t_credstore.o \
+ t_enctypes.o t_err.o t_export_cred.o t_export_name.o t_gssexts.o \
+- t_imp_cred.o t_imp_name.o t_inq_cred.o t_inq_mechs_name.o t_iov.o \
+- t_namingexts.o t_oid.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
++ t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o t_inq_mechs_name.o \
++ t_iov.o t_namingexts.o t_oid.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
+ t_spnego.o
+
+ COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+ COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+
+ all:: ccinit ccrefresh t_accname t_ccselect t_credstore t_enctypes t_err \
+- t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name \
++ t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name t_invalid \
+ t_inq_cred t_inq_mechs_name t_iov t_namingexts t_oid t_s4u \
+ t_s4u2proxy_krb5 t_saslname t_spnego
+
+ check-unix:: t_oid
++ $(RUN_SETUP) $(VALGRIND) ./t_invalid
+ $(RUN_SETUP) $(VALGRIND) ./t_oid
+
+ check-pytests:: ccinit ccrefresh t_accname t_ccselect t_credstore t_enctypes \
+@@ -70,6 +72,8 @@ t_imp_cred: t_imp_cred.o $(COMMON_DEPS)
+ $(CC_LINK) -o $@ t_imp_cred.o $(COMMON_LIBS)
+ t_imp_name: t_imp_name.o $(COMMON_DEPS)
+ $(CC_LINK) -o $@ t_imp_name.o $(COMMON_LIBS)
++t_invalid: t_invalid.o $(COMMON_DEPS)
++ $(CC_LINK) -o $@ t_invalid.o $(COMMON_LIBS)
+ t_inq_cred: t_inq_cred.o $(COMMON_DEPS)
+ $(CC_LINK) -o $@ t_inq_cred.o $(COMMON_LIBS)
+ t_inq_mechs_name: t_inq_mechs_name.o $(COMMON_DEPS)
+@@ -94,5 +98,5 @@ t_spnego: t_spnego.o $(COMMON_DEPS)
+ clean::
+ $(RM) ccinit ccrefresh t_accname t_ccselect t_credstore t_enctypes
+ $(RM) t_err t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name
+- $(RM) t_inq_cred t_inq_mechs_name t_iov t_namingexts t_oid t_s4u
+- $(RM) t_s4u2proxy_krb5 t_saslname t_spnego
++ $(RM) t_invalid t_inq_cred t_inq_mechs_name t_iov t_namingexts t_oid
++ $(RM) t_s4u t_s4u2proxy_krb5 t_saslname t_spnego
+diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps
+index c76d4ca..0a82d5d 100644
+--- a/src/tests/gssapi/deps
++++ b/src/tests/gssapi/deps
+@@ -75,6 +75,24 @@ $(OUTPRE)t_imp_name.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+ common.h t_imp_name.c
++$(OUTPRE)t_invalid.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
++ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
++ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
++ $(BUILDTOP)/include/profile.h $(BUILDTOP)/lib/gssapi/generic/gssapi_err_generic.h \
++ $(BUILDTOP)/lib/gssapi/krb5/gssapi_err_krb5.h $(COM_ERR_DEPS) \
++ $(srcdir)/../../lib/gssapi/generic/gssapiP_generic.h \
++ $(srcdir)/../../lib/gssapi/generic/gssapi_ext.h $(srcdir)/../../lib/gssapi/generic/gssapi_generic.h \
++ $(srcdir)/../../lib/gssapi/krb5/gssapiP_krb5.h $(srcdir)/../../lib/gssapi/krb5/gssapi_krb5.h \
++ $(srcdir)/../../lib/gssapi/mechglue/mechglue.h $(srcdir)/../../lib/gssapi/mechglue/mglueP.h \
++ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
++ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
++ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
++ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
++ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
++ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
++ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
++ common.h t_invalid.c
+ $(OUTPRE)t_inq_cred.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
+new file mode 100644
+index 0000000..5c8ddac
+--- /dev/null
++++ b/src/tests/gssapi/t_invalid.c
+@@ -0,0 +1,429 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* tests/gssapi/t_invalid.c - Invalid message token regression tests */
++/*
++ * Copyright (C) 2014 by the Massachusetts Institute of Technology.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
++ * COPYRIGHT HOLDER 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.
++ */
++
++/*
++ * This file contains regression tests for some GSSAPI krb5 invalid per-message
++ * token vulnerabilities.
++ *
++ * 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a
++ * null pointer dereference. (The token must use SEAL_ALG_NONE or it will
++ * be rejected.)
++ *
++ * 2. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
++ * header causes an input buffer overrun, usually leading to either a segv
++ * or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or
++ * sequence number values.
++ *
++ * 3. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
++ * header causes an integer underflow when computing the ciphertext length,
++ * leading to an allocation error on 32-bit platforms or a segv on 64-bit
++ * platforms. A pre-CFX MIC token of this size causes an input buffer
++ * overrun when comparing the checksum, perhaps leading to a segv.
++ *
++ * 4. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
++ * ciphertext (where padlen is the last byte of the decrypted ciphertext)
++ * causes an integer underflow when computing the original message length,
++ * leading to an allocation error.
++ *
++ * Vulnerabilities #1 and #2 also apply to IOV unwrap, although tokens with
++ * fewer than 16 bytes after the ASN.1 header will be rejected. Vulnerability
++ * #2 can only be robustly detected using a memory-checking environment such as
++ * valgrind.
++ */
++
++#include "k5-int.h"
++#include "common.h"
++#include "mglueP.h"
++#include "gssapiP_krb5.h"
++
++/*
++ * The following samples contain context parameters and otherwise valid seal
++ * tokens where the plain text is padded with byte value 100 instead of the
++ * proper value 1.
++ */
++struct test {
++ krb5_enctype enctype;
++ krb5_enctype encseq_enctype;
++ int sealalg;
++ int signalg;
++ size_t cksum_size;
++ size_t keylen;
++ const char *keydata;
++ size_t toklen;
++ const char *token;
++} tests[] = {
++ {
++ ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_RAW,
++ SEAL_ALG_DES, SGN_ALG_DES_MAC_MD5, 8,
++ 8,
++ "\x26\xEC\xBA\xB6\xFE\xBA\x91\xCE",
++ 53,
++ "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x00"
++ "\x00\x00\x00\xFF\xFF\xF0\x0B\x90\x7B\xC4\xFC\xEB\xF4\x84\x9C\x5A"
++ "\xA8\x56\x41\x3E\xE1\x62\xEE\x38\xD1\x34\x9A\xE3\xFB\xC9\xFD\x0A"
++ "\xDC\x83\xE1\x4A\xE4"
++ },
++ {
++ ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,
++ SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,
++ 24,
++ "\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"
++ "\x92\x3D\x38\xF7\x26\x73\x0D\x6D",
++ 65,
++ "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
++ "\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"
++ "\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"
++ "\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4"
++ },
++ {
++ ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,
++ SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,
++ 16,
++ "\x66\x64\x41\x64\x55\x78\x21\xD0\xD0\xFD\x05\x6A\xFF\x6F\xE8\x09",
++ 53,
++ "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
++ "\x00\x10\x00\xFF\xFF\x35\xD4\x79\xF3\x8C\x47\x8F\x6E\x23\x6F\x3E"
++ "\xCC\x5E\x57\x5C\x6A\x89\xF0\xA2\x03\x4F\x0B\x51\x11\xEE\x89\x7E"
++ "\xD6\xF6\xB5\xD6\x51"
++ }
++};
++
++/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */
++static gss_ctx_id_t
++make_fake_cfx_context()
++{
++ gss_union_ctx_id_t uctx;
++ krb5_gss_ctx_id_t kgctx;
++ krb5_keyblock kb;
++
++ kgctx = calloc(1, sizeof(*kgctx));
++ if (kgctx == NULL)
++ abort();
++ kgctx->established = 1;
++ kgctx->proto = 1;
++ if (g_order_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
++ abort();
++ kgctx->mech_used = &mech_krb5;
++ kgctx->sealalg = -1;
++ kgctx->signalg = -1;
++
++ kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
++ kb.length = 16;
++ kb.contents = (unsigned char *)"1234567887654321";
++ if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
++ abort();
++
++ uctx = calloc(1, sizeof(*uctx));
++ if (uctx == NULL)
++ abort();
++ uctx->mech_type = &mech_krb5;
++ uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
++ return (gss_ctx_id_t)uctx;
++}
++
++/* Fake up enough of a GSS context for gss_unwrap, using keys from test. */
++static gss_ctx_id_t
++make_fake_context(const struct test *test)
++{
++ gss_union_ctx_id_t uctx;
++ krb5_gss_ctx_id_t kgctx;
++ krb5_keyblock kb;
++ unsigned char encbuf[8];
++ size_t i;
++
++ kgctx = calloc(1, sizeof(*kgctx));
++ if (kgctx == NULL)
++ abort();
++ kgctx->established = 1;
++ if (g_order_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
++ abort();
++ kgctx->mech_used = &mech_krb5;
++ kgctx->sealalg = test->sealalg;
++ kgctx->signalg = test->signalg;
++ kgctx->cksum_size = test->cksum_size;
++
++ kb.enctype = test->enctype;
++ kb.length = test->keylen;
++ kb.contents = (unsigned char *)test->keydata;
++ if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
++ abort();
++
++ kb.enctype = test->encseq_enctype;
++ if (krb5_k_create_key(NULL, &kb, &kgctx->seq) != 0)
++ abort();
++
++ if (kb.enctype == ENCTYPE_DES_CBC_RAW) {
++ for (i = 0; i < 8; i++)
++ encbuf[i] = kb.contents[i] ^ 0xF0;
++ kb.contents = encbuf;
++ }
++ if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
++ abort();
++
++ uctx = calloc(1, sizeof(*uctx));
++ if (uctx == NULL)
++ abort();
++ uctx->mech_type = &mech_krb5;
++ uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
++ return (gss_ctx_id_t)uctx;
++}
++
++/* Free a context created by make_fake_context. */
++static void
++free_fake_context(gss_ctx_id_t ctx)
++{
++ gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx;
++ krb5_gss_ctx_id_t kgctx = (krb5_gss_ctx_id_t)uctx->internal_ctx_id;
++
++ free(kgctx->seqstate);
++ krb5_k_free_key(NULL, kgctx->subkey);
++ krb5_k_free_key(NULL, kgctx->seq);
++ krb5_k_free_key(NULL, kgctx->enc);
++ free(kgctx);
++ free(uctx);
++}
++
++/* Prefix a token (starting at the two-byte ID) with an ASN.1 header and return
++ * it in an allocated block to facilitate checking by valgrind or similar. */
++static void
++make_token(unsigned char *token, size_t len, gss_buffer_t out)
++{
++ char *wrapped;
++
++ assert(mech_krb5.length == 9);
++ assert(len + 11 < 128);
++ wrapped = malloc(len + 13);
++ if (wrapped == NULL)
++ abort();
++ wrapped[0] = 0x60;
++ wrapped[1] = len + 11;
++ wrapped[2] = 0x06;
++ wrapped[3] = 9;
++ memcpy(wrapped + 4, mech_krb5.elements, 9);
++ memcpy(wrapped + 13, token, len);
++ out->length = len + 13;
++ out->value = wrapped;
++}
++
++/* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
++ * regular and IOV unwrap. */
++static void
++test_bogus_1964_token(gss_ctx_id_t ctx)
++{
++ OM_uint32 minor, major;
++ unsigned char tokbuf[128];
++ gss_buffer_desc in, out;
++ gss_iov_buffer_desc iov;
++
++ store_16_be(KG_TOK_SIGN_MSG, tokbuf);
++ store_16_le(SGN_ALG_DES_MAC_MD5, tokbuf + 2);
++ store_16_le(SEAL_ALG_NONE, tokbuf + 4);
++ store_16_le(0xFFFF, tokbuf + 6);
++ memset(tokbuf + 8, 0, 16);
++ make_token(tokbuf, 24, &in);
++
++ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ (void)gss_release_buffer(&minor, &out);
++
++ iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
++ iov.buffer = in;
++ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++
++ free(in.value);
++}
++
++/* Process wrap and MIC tokens with incomplete headers. */
++static void
++test_short_header(gss_ctx_id_t ctx)
++{
++ OM_uint32 minor, major;
++ unsigned char tokbuf[128];
++ gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
++
++ /* Seal token, 2-24 bytes */
++ store_16_be(KG_TOK_SEAL_MSG, tokbuf);
++ make_token(tokbuf, 2, &in);
++ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(in.value);
++ (void)gss_release_buffer(&minor, &out);
++
++ /* Sign token, 2-24 bytes */
++ store_16_be(KG_TOK_SIGN_MSG, tokbuf);
++ make_token(tokbuf, 2, &in);
++ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(in.value);
++ (void)gss_release_buffer(&minor, &out);
++
++ /* MIC token, 2-24 bytes */
++ store_16_be(KG_TOK_MIC_MSG, tokbuf);
++ make_token(tokbuf, 2, &in);
++ major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(in.value);
++}
++
++/* Process wrap and MIC tokens with incomplete headers. */
++static void
++test_short_header_iov(gss_ctx_id_t ctx, const struct test *test)
++{
++ OM_uint32 minor, major;
++ unsigned char tokbuf[128];
++ gss_iov_buffer_desc iov;
++
++ /* IOV seal token, 16-23 bytes */
++ store_16_be(KG_TOK_SEAL_MSG, tokbuf);
++ store_16_le(test->signalg, tokbuf + 2);
++ store_16_le(test->sealalg, tokbuf + 4);
++ store_16_be(0xFFFF, tokbuf + 6);
++ memset(tokbuf + 8, 0, 8);
++ iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
++ make_token(tokbuf, 16, &iov.buffer);
++ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(iov.buffer.value);
++
++ /* IOV sign token, 16-23 bytes */
++ store_16_be(KG_TOK_SIGN_MSG, tokbuf);
++ store_16_le(test->signalg, tokbuf + 2);
++ store_16_le(SEAL_ALG_NONE, tokbuf + 4);
++ store_16_le(0xFFFF, tokbuf + 6);
++ memset(tokbuf + 8, 0, 8);
++ iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
++ make_token(tokbuf, 16, &iov.buffer);
++ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(iov.buffer.value);
++
++ /* IOV MIC token, 16-23 bytes */
++ store_16_be(KG_TOK_MIC_MSG, tokbuf);
++ store_16_be(test->signalg, tokbuf + 2);
++ store_16_le(SEAL_ALG_NONE, tokbuf + 4);
++ store_16_le(0xFFFF, tokbuf + 6);
++ memset(tokbuf + 8, 0, 8);
++ iov.type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
++ make_token(tokbuf, 16, &iov.buffer);
++ major = gss_verify_mic_iov(&minor, ctx, NULL, &iov, 1);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(iov.buffer.value);
++}
++
++/* Process wrap and MIC tokens with incomplete checksums. */
++static void
++test_short_checksum(gss_ctx_id_t ctx, const struct test *test)
++{
++ OM_uint32 minor, major;
++ unsigned char tokbuf[128];
++ gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
++
++ /* Can only do this with the DES3 checksum, as we can't easily get past
++ * retrieving the sequence number when the checksum is only eight bytes. */
++ if (test->cksum_size <= 8)
++ return;
++ /* Seal token, fewer than 16 + cksum_size bytes. Use the token from the
++ * test data to get a valid sequence number. */
++ make_token((unsigned char *)test->token + 13, 24, &in);
++ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(in.value);
++ (void)gss_release_buffer(&minor, &out);
++
++ /* Sign token, fewer than 16 + cksum_size bytes. */
++ memcpy(tokbuf, test->token + 13, 24);
++ store_16_be(KG_TOK_SIGN_MSG, tokbuf);
++ store_16_le(SEAL_ALG_NONE, tokbuf + 4);
++ make_token(tokbuf, 24, &in);
++ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(in.value);
++ (void)gss_release_buffer(&minor, &out);
++
++ /* MIC token, fewer than 16 + cksum_size bytes. */
++ memcpy(tokbuf, test->token + 13, 24);
++ store_16_be(KG_TOK_MIC_MSG, tokbuf);
++ store_16_le(SEAL_ALG_NONE, tokbuf + 4);
++ make_token(tokbuf, 24, &in);
++ major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
++ if (major != GSS_S_DEFECTIVE_TOKEN)
++ abort();
++ free(in.value);
++}
++
++/* Unwrap a token with a bogus padding byte in the decrypted ciphertext. */
++static void
++test_bad_pad(gss_ctx_id_t ctx, const struct test *test)
++{
++ OM_uint32 minor, major;
++ gss_buffer_desc in, out;
++
++ in.length = test->toklen;
++ in.value = (char *)test->token;
++ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
++ if (major != GSS_S_BAD_SIG)
++ abort();
++ (void)gss_release_buffer(&minor, &out);
++}
++
++int
++main(int argc, char **argv)
++{
++ gss_ctx_id_t ctx;
++ size_t i;
++
++ ctx = make_fake_cfx_context();
++ test_bogus_1964_token(ctx);
++ free_fake_context(ctx);
++
++ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
++ ctx = make_fake_context(&tests[i]);
++ test_short_header(ctx);
++ test_short_header_iov(ctx, &tests[i]);
++ test_short_checksum(ctx, &tests[i]);
++ test_bad_pad(ctx, &tests[i]);
++ free_fake_context(ctx);
++ }
++
++ return 0;
++}