Path: blob/main/crypto/krb5/src/tests/gssapi/t_invalid.c
34889 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* tests/gssapi/t_invalid.c - Invalid message token regression tests */2/*3* Copyright (C) 2014 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132/*33* This file contains regression tests for some GSSAPI invalid token34* vulnerabilities.35*36* 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a37* null pointer dereference. (The token must use SEAL_ALG_NONE or it will38* be rejected.) This vulnerability also applies to IOV unwrap.39*40* 2. A CFX wrap token with a different value of EC between the plaintext and41* encrypted copies will be erroneously accepted, which allows a message42* truncation attack. This vulnerability also applies to IOV unwrap.43*44* 3. A CFX wrap token with a plaintext length fewer than 16 bytes causes an45* access before the beginning of the input buffer, possibly leading to a46* crash.47*48* 4. A CFX wrap token with a plaintext EC value greater than the plaintext49* length - 16 causes an integer underflow when computing the result length,50* likely causing a crash.51*52* 5. An IOV unwrap operation will overrun the header buffer if an ASN.153* wrapper longer than the header buffer is present.54*55* 6. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.156* header causes an input buffer overrun, usually leading to either a segv57* or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or58* sequence number values. This vulnerability also applies to IOV unwrap.59*60* 7. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.161* header causes an integer underflow when computing the ciphertext length,62* leading to an allocation error on 32-bit platforms or a segv on 64-bit63* platforms. A pre-CFX MIC token of this size causes an input buffer64* overrun when comparing the checksum, perhaps leading to a segv.65*66* 8. A pre-CFX wrap token with fewer than conflen + padlen bytes in the67* ciphertext (where padlen is the last byte of the decrypted ciphertext)68* causes an integer underflow when computing the original message length,69* leading to an allocation error.70*71* 9. In the mechglue, truncated encapsulation in the initial context token can72* cause input buffer overruns in gss_accept_sec_context().73*/7475#include "k5-int.h"76#include "common.h"77#include "mglueP.h"78#include "gssapiP_krb5.h"7980/*81* The following samples contain:82* - context parameters83* - otherwise valid seal tokens where the plain text is padded with byte value84* 100 instead of the proper value 1.85* - valid MIC tokens for the message "message"86* - two valid wrap tokens for the message "message", one without87* confidentiality and one with88*/89struct test {90krb5_enctype enctype;91krb5_enctype encseq_enctype;92int sealalg;93int signalg;94size_t cksum_size;95size_t keylen;96const char *keydata;97size_t toklen;98const char *token;99size_t miclen;100const char *mic;101size_t wrap1len;102const char *wrap1;103size_t wrap2len;104const char *wrap2;105} tests[] = {106{107ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,108SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,10924,110"\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"111"\x92\x3D\x38\xF7\x26\x73\x0D\x6D",11265,113"\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"114"\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"115"\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"116"\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4",11749,118"\x60\x2F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01\x01\x04"119"\x00\xFF\xFF\xFF\xFF\x57\xF5\x77\xC6\xC0\x72\x26\x97\x00\x89\xB2"120"\xEE\xD9\xD1\x90\xE7\x11\x50\x4F\xE9\x59\x18\xB1\x8F\x82\x8E\x8F\x5E",12165,122"\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"123"\x00\xFF\xFF\xFF\xFF\x0B\x81\x56\x4A\x02\x1B\xBE\x83\x2B\x35\x08"124"\x7B\x49\x15\x07\x97\x6A\x64\xEF\xDD\x32\x52\xF0\xA2\xE2\x62\x9B"125"\xA7\x72\xF7\x3D\x6B\x2D\xAC\x21\xE9\x6D\x65\x73\x73\x61\x67\x65\x01",12665,127"\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"128"\x00\x02\x00\xFF\xFF\x66\x5A\xE1\xC8\x4F\x69\x33\x97\x5D\x05\xE2"129"\x86\x40\x14\x15\x14\x27\x01\x9F\x32\x9D\x82\xF4\xE1\xC5\x3E\xFA"130"\x6D\x7D\x05\x39\xAE\x21\x44\xA0\x87\xA6\x24\xED\xFC\xA3\x53\xF1\x30"131},132{133ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,134SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,13516,136"\x66\x64\x41\x64\x55\x78\x21\xD0\xD0\xFD\x05\x6A\xFF\x6F\xE8\x09",13753,138"\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"139"\x00\x10\x00\xFF\xFF\x35\xD4\x79\xF3\x8C\x47\x8F\x6E\x23\x6F\x3E"140"\xCC\x5E\x57\x5C\x6A\x89\xF0\xA2\x03\x4F\x0B\x51\x11\xEE\x89\x7E"141"\xD6\xF6\xB5\xD6\x51",14237,143"\x60\x23\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01\x01\x11"144"\x00\xFF\xFF\xFF\xFF\x5D\xE7\x51\xF6\xFB\x6C\x25\x5B\x23\x93\x5A"145"\x30\x20\x57\xDC\xB5",14653,147"\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"148"\x00\xFF\xFF\xFF\xFF\xAD\xB5\x1D\x01\x39\x7B\xA2\x16\x4C\x1B\x68"149"\x18\xEC\xAC\xD9\xE5\x9E\xD1\x41\x7A\x89\xE8\xCB\x24\x6D\x65\x73"150"\x73\x61\x67\x65\x01",15153,152"\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"153"\x00\x10\x00\xFF\xFF\xDD\x6D\x04\xEA\x64\x5C\xE7\x31\x50\xD0\x09"154"\x44\x9E\x67\xA4\x30\xEC\xFB\xFF\xC0\xF7\x16\x1E\x14\x1A\x82\x42"155"\xDD\x26\x23\x2B\x02"156}157};158159static void *160ealloc(size_t len)161{162void *ptr = calloc(len, 1);163164if (ptr == NULL)165abort();166return ptr;167}168169/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.170* The context takes ownership of subkey. */171static gss_ctx_id_t172make_fake_cfx_context(krb5_key subkey)173{174gss_union_ctx_id_t uctx;175krb5_gss_ctx_id_t kgctx;176177kgctx = ealloc(sizeof(*kgctx));178kgctx->established = 1;179kgctx->proto = 1;180if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)181abort();182kgctx->mech_used = &mech_krb5;183kgctx->sealalg = -1;184kgctx->signalg = -1;185186kgctx->subkey = subkey;187kgctx->cksumtype = CKSUMTYPE_HMAC_SHA1_96_AES128;188189uctx = ealloc(sizeof(*uctx));190uctx->mech_type = &mech_krb5;191uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;192return (gss_ctx_id_t)uctx;193}194195/* Fake up enough of a GSS context for gss_unwrap, using keys from test. */196static gss_ctx_id_t197make_fake_context(const struct test *test)198{199gss_union_ctx_id_t uctx;200krb5_gss_ctx_id_t kgctx;201krb5_keyblock kb;202203kgctx = ealloc(sizeof(*kgctx));204kgctx->established = 1;205if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)206abort();207kgctx->mech_used = &mech_krb5;208kgctx->sealalg = test->sealalg;209kgctx->signalg = test->signalg;210kgctx->cksum_size = test->cksum_size;211212kb.enctype = test->enctype;213kb.length = test->keylen;214kb.contents = (unsigned char *)test->keydata;215if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)216abort();217218kb.enctype = test->encseq_enctype;219if (krb5_k_create_key(NULL, &kb, &kgctx->seq) != 0)220abort();221222if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)223abort();224225uctx = ealloc(sizeof(*uctx));226uctx->mech_type = &mech_krb5;227uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;228return (gss_ctx_id_t)uctx;229}230231/* Free a context created by make_fake_context. */232static void233free_fake_context(gss_ctx_id_t ctx)234{235gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx;236krb5_gss_ctx_id_t kgctx = (krb5_gss_ctx_id_t)uctx->internal_ctx_id;237238free(kgctx->seqstate);239krb5_k_free_key(NULL, kgctx->subkey);240krb5_k_free_key(NULL, kgctx->seq);241krb5_k_free_key(NULL, kgctx->enc);242free(kgctx);243free(uctx);244}245246/* Prefix a token (starting at the two-byte ID) with an ASN.1 header and return247* it in an allocated block to facilitate checking by valgrind or similar. */248static void249make_token(unsigned char *token, size_t len, gss_buffer_t out)250{251char *wrapped;252253assert(mech_krb5.length == 9);254assert(len + 11 < 128);255wrapped = ealloc(len + 13);256wrapped[0] = 0x60;257wrapped[1] = len + 11;258wrapped[2] = 0x06;259wrapped[3] = 9;260memcpy(wrapped + 4, mech_krb5.elements, 9);261memcpy(wrapped + 13, token, len);262out->length = len + 13;263out->value = wrapped;264}265266/* Create a 16-byte header for a CFX confidential wrap token to be processed by267* the fake CFX context. */268static void269write_cfx_header(uint16_t ec, uint8_t *out)270{271memset(out, 0, 16);272store_16_be(KG2_TOK_WRAP_MSG, out);273out[2] = FLAG_WRAP_CONFIDENTIAL;274out[3] = 0xFF;275store_16_be(ec, out + 4);276}277278/* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with279* regular and IOV unwrap. */280static void281test_bogus_1964_token(gss_ctx_id_t ctx)282{283OM_uint32 minor, major;284unsigned char tokbuf[128];285gss_buffer_desc in, out;286gss_iov_buffer_desc iov;287288store_16_be(KG_TOK_SIGN_MSG, tokbuf);289store_16_le(SGN_ALG_HMAC_MD5, tokbuf + 2);290store_16_le(SEAL_ALG_NONE, tokbuf + 4);291store_16_le(0xFFFF, tokbuf + 6);292memset(tokbuf + 8, 0, 16);293make_token(tokbuf, 24, &in);294295major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);296if (major != GSS_S_DEFECTIVE_TOKEN)297abort();298(void)gss_release_buffer(&minor, &out);299300iov.type = GSS_IOV_BUFFER_TYPE_HEADER;301iov.buffer = in;302major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);303if (major != GSS_S_DEFECTIVE_TOKEN)304abort();305306free(in.value);307}308309static void310test_cfx_altered_ec(gss_ctx_id_t ctx, krb5_key subkey)311{312OM_uint32 major, minor;313uint8_t tokbuf[128], plainbuf[24];314krb5_data plain;315krb5_enc_data cipher;316gss_buffer_desc in, out;317gss_iov_buffer_desc iov[2];318319/* Construct a header with a plaintext EC value of 3. */320write_cfx_header(3, tokbuf);321322/* Encrypt a plaintext and a copy of the header with the EC value 0. */323memcpy(plainbuf, "truncate", 8);324memcpy(plainbuf + 8, tokbuf, 16);325store_16_be(0, plainbuf + 12);326plain = make_data(plainbuf, 24);327cipher.ciphertext.data = (char *)tokbuf + 16;328cipher.ciphertext.length = sizeof(tokbuf) - 16;329cipher.enctype = subkey->keyblock.enctype;330if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,331&plain, &cipher) != 0)332abort();333334/* Verify that the token is rejected by gss_unwrap(). */335in.value = tokbuf;336in.length = 16 + cipher.ciphertext.length;337major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);338if (major != GSS_S_DEFECTIVE_TOKEN)339abort();340(void)gss_release_buffer(&minor, &out);341342/* Verify that the token is rejected by gss_unwrap_iov(). */343iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;344iov[0].buffer = in;345iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;346major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);347if (major != GSS_S_DEFECTIVE_TOKEN)348abort();349}350351static void352test_cfx_short_plaintext(gss_ctx_id_t ctx, krb5_key subkey)353{354OM_uint32 major, minor;355uint8_t tokbuf[128], zerobyte = 0;356krb5_data plain;357krb5_enc_data cipher;358gss_buffer_desc in, out;359360write_cfx_header(0, tokbuf);361362/* Encrypt a single byte, with no copy of the header. */363plain = make_data(&zerobyte, 1);364cipher.ciphertext.data = (char *)tokbuf + 16;365cipher.ciphertext.length = sizeof(tokbuf) - 16;366cipher.enctype = subkey->keyblock.enctype;367if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,368&plain, &cipher) != 0)369abort();370371/* Verify that the token is rejected by gss_unwrap(). */372in.value = tokbuf;373in.length = 16 + cipher.ciphertext.length;374major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);375if (major != GSS_S_DEFECTIVE_TOKEN)376abort();377(void)gss_release_buffer(&minor, &out);378}379380static void381test_cfx_large_ec(gss_ctx_id_t ctx, krb5_key subkey)382{383OM_uint32 major, minor;384uint8_t tokbuf[128] = { 0 }, plainbuf[20];385krb5_data plain;386krb5_enc_data cipher;387gss_buffer_desc in, out;388389/* Construct a header with an EC value of 5. */390write_cfx_header(5, tokbuf);391392/* Encrypt a 4-byte plaintext plus the header. */393memcpy(plainbuf, "abcd", 4);394memcpy(plainbuf + 4, tokbuf, 16);395plain = make_data(plainbuf, 20);396cipher.ciphertext.data = (char *)tokbuf + 16;397cipher.ciphertext.length = sizeof(tokbuf) - 16;398cipher.enctype = subkey->keyblock.enctype;399if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,400&plain, &cipher) != 0)401abort();402403/* Verify that the token is rejected by gss_unwrap(). */404in.value = tokbuf;405in.length = 16 + cipher.ciphertext.length;406major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);407if (major != GSS_S_DEFECTIVE_TOKEN)408abort();409(void)gss_release_buffer(&minor, &out);410}411412static void413test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)414{415OM_uint32 minor, major;416uint8_t databuf[10] = { 0 };417gss_iov_buffer_desc iov[2];418419/*420* In this IOV array, the header contains a DER tag with a dangling eight421* bytes of length field. The data IOV indicates a total token length422* sufficient to contain the length bytes.423*/424iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;425iov[0].buffer.value = ealloc(2);426iov[0].buffer.length = 2;427memcpy(iov[0].buffer.value, "\x60\x88", 2);428iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;429iov[1].buffer.value = databuf;430iov[1].buffer.length = 10;431major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);432if (major != GSS_S_DEFECTIVE_TOKEN)433abort();434free(iov[0].buffer.value);435}436437/* Verify that token is a valid MIC token for ctx and message, and that438* changing any of the input bytes yields one of the expected errors. */439static void440mictest(gss_ctx_id_t ctx, gss_buffer_t message, gss_buffer_t token)441{442OM_uint32 major, minor;443size_t i;444uint8_t *p;445446major = gss_verify_mic(&minor, ctx, message, token, NULL);447check_gsserr("gss_verify_mic", major, minor);448449p = token->value;450for (i = 0; i < token->length; i++) {451/* Skip sequence number bytes for RC4. */452if (load_16_le(p + 15) == SGN_ALG_HMAC_MD5 && i >= 21 && i <= 24)453continue;454p[i]++;455major = gss_verify_mic(&minor, ctx, message, token, NULL);456if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG)457abort();458p[i]--;459}460p = message->value;461for (i = 0; i < message->length; i++) {462p[i]++;463major = gss_verify_mic(&minor, ctx, message, token, NULL);464if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG)465abort();466p[i]--;467}468}469470static void471test_cfx_verify_mic(gss_ctx_id_t ctx)472{473gss_buffer_desc message, token;474uint8_t msg[] = "message";475uint8_t mic[] = "\x04\x04\x00\xFF\xFF\xFF\xFF\xFF"476"\x00\x00\x00\x00\x00\x00\x00\x00\x97\xE9\x63\x3F\x9D\x82\x2B\x74"477"\x67\x94\x8A\xD0";478479message.value = msg;480message.length = sizeof(msg) - 1;481token.value = mic;482token.length = sizeof(mic) - 1;483mictest(ctx, &message, &token);484}485486static void487test_verify_mic(gss_ctx_id_t ctx, const struct test *test)488{489gss_buffer_desc message, token;490uint8_t msg[] = "message", buf[128];491492assert(test->miclen <= sizeof(buf));493memcpy(buf, test->mic, test->miclen);494495message.value = msg;496message.length = sizeof(msg) - 1;497token.value = buf;498token.length = test->miclen;499mictest(ctx, &message, &token);500}501502/* Verify that token is a valid wrap token for ctx unwrapping to message, and503* that changing any of the token bytes yields one of the expected errors. */504static void505unwraptest(gss_ctx_id_t ctx, gss_buffer_t message, gss_buffer_t token)506{507OM_uint32 major, minor;508gss_buffer_desc unwrapped;509size_t i;510uint8_t *p;511512major = gss_unwrap(&minor, ctx, token, &unwrapped, NULL, NULL);513check_gsserr("gss_unwrap", major, minor);514if (unwrapped.length != message->length ||515memcmp(unwrapped.value, message->value, unwrapped.length) != 0)516abort();517gss_release_buffer(&minor, &unwrapped);518519p = token->value;520for (i = 0; i < token->length; i++) {521/* Skip sequence number bytes for RC4. */522if (load_16_le(p + 15) == SGN_ALG_HMAC_MD5 && i >= 21 && i <= 24)523continue;524p[i]++;525major = gss_unwrap(&minor, ctx, token, &unwrapped, NULL, NULL);526if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG)527abort();528p[i]--;529}530}531532static void533test_cfx_unwrap(gss_ctx_id_t ctx)534{535gss_buffer_desc message, token;536uint8_t msg[] = "message";537uint8_t token1[] = "\x05\x04\x00\xFF\x00\x0C\x00\x00"538"\x00\x00\x00\x00\x00\x00\x00\x00\x6D\x65\x73\x73\x61\x67\x65\xDF"539"\x57\xB9\x5E\xA2\xB1\x73\x31\xDB\xCE\x61\x62";540uint8_t token2[] = "\x05\x04\x02\xFF\x00\x00\x00\x00"541"\x00\x00\x00\x00\x00\x00\x00\x00\x72\xBB\xD7\xCF\xDE\xB0\xF9\x20"542"\xE2\x9A\x98\xA7\xA4\xE7\xC9\x9B\x30\xD3\xFE\x61\x51\x2E\x1B\x56"543"\x88\xB7\x8A\xF5\xA9\xBF\x8F\x82\xB1\xEB\xCC\x88\xE6\x33\x13\xBF"544"\x52\x4B\xC0\x3B\x24\x3F\x3E\xF5\xF1\xE0\x64";545546message.value = msg;547message.length = sizeof(msg) - 1;548token.value = token1;549token.length = sizeof(token1) - 1;550unwraptest(ctx, &message, &token);551token.value = token2;552token.length = sizeof(token2) - 1;553unwraptest(ctx, &message, &token);554}555556static void557test_unwrap(gss_ctx_id_t ctx, const struct test *test)558{559gss_buffer_desc message, token;560uint8_t msg[] = "message", buf[128];561562assert(test->wrap1len <= sizeof(buf) && test->wrap2len <= sizeof(buf));563token.value = buf;564565message.value = msg;566message.length = sizeof(msg) - 1;567memcpy(buf, test->wrap1, test->wrap1len);568token.length = test->wrap1len;569unwraptest(ctx, &message, &token);570memcpy(buf, test->wrap2, test->wrap2len);571token.length = test->wrap2len;572unwraptest(ctx, &message, &token);573}574575/* Process wrap and MIC tokens with incomplete headers. */576static void577test_short_header(gss_ctx_id_t ctx)578{579OM_uint32 minor, major;580unsigned char tokbuf[128];581gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;582583/* Seal token, 2-24 bytes */584store_16_be(KG_TOK_SEAL_MSG, tokbuf);585make_token(tokbuf, 2, &in);586major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);587if (major != GSS_S_DEFECTIVE_TOKEN)588abort();589free(in.value);590(void)gss_release_buffer(&minor, &out);591592/* Sign token, 2-24 bytes */593store_16_be(KG_TOK_SIGN_MSG, tokbuf);594make_token(tokbuf, 2, &in);595major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);596if (major != GSS_S_DEFECTIVE_TOKEN)597abort();598free(in.value);599(void)gss_release_buffer(&minor, &out);600601/* MIC token, 2-24 bytes */602store_16_be(KG_TOK_MIC_MSG, tokbuf);603make_token(tokbuf, 2, &in);604major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);605if (major != GSS_S_DEFECTIVE_TOKEN)606abort();607free(in.value);608}609610/* Process wrap and MIC tokens with incomplete headers. */611static void612test_short_header_iov(gss_ctx_id_t ctx, const struct test *test)613{614OM_uint32 minor, major;615unsigned char tokbuf[128];616gss_iov_buffer_desc iov;617618/* IOV seal token, 16-23 bytes */619store_16_be(KG_TOK_SEAL_MSG, tokbuf);620store_16_le(test->signalg, tokbuf + 2);621store_16_le(test->sealalg, tokbuf + 4);622store_16_be(0xFFFF, tokbuf + 6);623memset(tokbuf + 8, 0, 8);624iov.type = GSS_IOV_BUFFER_TYPE_HEADER;625make_token(tokbuf, 16, &iov.buffer);626major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);627if (major != GSS_S_DEFECTIVE_TOKEN)628abort();629free(iov.buffer.value);630631/* IOV sign token, 16-23 bytes */632store_16_be(KG_TOK_SIGN_MSG, tokbuf);633store_16_le(test->signalg, tokbuf + 2);634store_16_le(SEAL_ALG_NONE, tokbuf + 4);635store_16_le(0xFFFF, tokbuf + 6);636memset(tokbuf + 8, 0, 8);637iov.type = GSS_IOV_BUFFER_TYPE_HEADER;638make_token(tokbuf, 16, &iov.buffer);639major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);640if (major != GSS_S_DEFECTIVE_TOKEN)641abort();642free(iov.buffer.value);643644/* IOV MIC token, 16-23 bytes */645store_16_be(KG_TOK_MIC_MSG, tokbuf);646store_16_be(test->signalg, tokbuf + 2);647store_16_le(SEAL_ALG_NONE, tokbuf + 4);648store_16_le(0xFFFF, tokbuf + 6);649memset(tokbuf + 8, 0, 8);650iov.type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;651make_token(tokbuf, 16, &iov.buffer);652major = gss_verify_mic_iov(&minor, ctx, NULL, &iov, 1);653if (major != GSS_S_DEFECTIVE_TOKEN)654abort();655free(iov.buffer.value);656}657658/* Process wrap and MIC tokens with incomplete checksums. */659static void660test_short_checksum(gss_ctx_id_t ctx, const struct test *test)661{662OM_uint32 minor, major;663unsigned char tokbuf[128];664gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;665666/* Can only do this with the DES3 checksum, as we can't easily get past667* retrieving the sequence number when the checksum is only eight bytes. */668if (test->cksum_size <= 8)669return;670/* Seal token, fewer than 16 + cksum_size bytes. Use the token from the671* test data to get a valid sequence number. */672make_token((unsigned char *)test->token + 13, 24, &in);673major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);674if (major != GSS_S_DEFECTIVE_TOKEN)675abort();676free(in.value);677(void)gss_release_buffer(&minor, &out);678679/* Sign token, fewer than 16 + cksum_size bytes. */680memcpy(tokbuf, test->token + 13, 24);681store_16_be(KG_TOK_SIGN_MSG, tokbuf);682store_16_le(SEAL_ALG_NONE, tokbuf + 4);683make_token(tokbuf, 24, &in);684major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);685if (major != GSS_S_DEFECTIVE_TOKEN)686abort();687free(in.value);688(void)gss_release_buffer(&minor, &out);689690/* MIC token, fewer than 16 + cksum_size bytes. */691memcpy(tokbuf, test->token + 13, 24);692store_16_be(KG_TOK_MIC_MSG, tokbuf);693store_16_le(SEAL_ALG_NONE, tokbuf + 4);694make_token(tokbuf, 24, &in);695major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);696if (major != GSS_S_DEFECTIVE_TOKEN)697abort();698free(in.value);699}700701/* Unwrap a token with a bogus padding byte in the decrypted ciphertext. */702static void703test_bad_pad(gss_ctx_id_t ctx, const struct test *test)704{705OM_uint32 minor, major;706gss_buffer_desc in, out;707708in.length = test->toklen;709in.value = (char *)test->token;710major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);711if (major != GSS_S_BAD_SIG)712abort();713(void)gss_release_buffer(&minor, &out);714}715716static void717try_accept(void *value, size_t len)718{719OM_uint32 minor;720gss_buffer_desc in, out;721gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;722723/* Copy the provided value to make input overruns more obvious. */724in.value = ealloc(len);725memcpy(in.value, value, len);726in.length = len;727(void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,728GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,729&out, NULL, NULL, NULL);730gss_release_buffer(&minor, &out);731gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);732free(in.value);733}734735/* Accept contexts using superficially valid but truncated encapsulations. */736static void737test_short_encapsulation(void)738{739/* Include just the initial application tag, to see if we overrun reading740* the sequence length. */741try_accept("\x60", 1);742743/* Indicate four additional sequence length bytes, to see if we overrun744* reading them (or skipping them and reading the next byte). */745try_accept("\x60\x84", 2);746747/* Include an object identifier tag but no length, to see if we overrun748* reading the length. */749try_accept("\x60\x40\x06", 3);750751/* Include an object identifier tag with a length matching the krb5 mech,752* but no OID bytes, to see if we overrun comparing against mechs. */753try_accept("\x60\x40\x06\x09", 4);754}755756int757main(int argc, char **argv)758{759krb5_keyblock kb;760krb5_key cfx_subkey;761gss_ctx_id_t ctx;762size_t i;763764kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;765kb.length = 16;766kb.contents = (unsigned char *)"1234567887654321";767if (krb5_k_create_key(NULL, &kb, &cfx_subkey) != 0)768abort();769770ctx = make_fake_cfx_context(cfx_subkey);771test_bogus_1964_token(ctx);772test_cfx_altered_ec(ctx, cfx_subkey);773test_cfx_short_plaintext(ctx, cfx_subkey);774test_cfx_large_ec(ctx, cfx_subkey);775test_iov_large_asn1_wrapper(ctx);776test_cfx_verify_mic(ctx);777test_cfx_unwrap(ctx);778free_fake_context(ctx);779780for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {781ctx = make_fake_context(&tests[i]);782test_short_header(ctx);783test_short_header_iov(ctx, &tests[i]);784test_short_checksum(ctx, &tests[i]);785test_bad_pad(ctx, &tests[i]);786test_verify_mic(ctx, &tests[i]);787test_unwrap(ctx, &tests[i]);788free_fake_context(ctx);789}790791test_short_encapsulation();792793return 0;794}795796797