xref: /freebsd/crypto/krb5/src/tests/gssapi/t_invalid.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/gssapi/t_invalid.c - Invalid message token regression tests */
3 /*
4  * Copyright (C) 2014 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * This file contains regression tests for some GSSAPI invalid token
35  * vulnerabilities.
36  *
37  * 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a
38  *    null pointer dereference.  (The token must use SEAL_ALG_NONE or it will
39  *    be rejected.)  This vulnerability also applies to IOV unwrap.
40  *
41  * 2. A CFX wrap token with a different value of EC between the plaintext and
42  *    encrypted copies will be erroneously accepted, which allows a message
43  *    truncation attack.  This vulnerability also applies to IOV unwrap.
44  *
45  * 3. A CFX wrap token with a plaintext length fewer than 16 bytes causes an
46  *    access before the beginning of the input buffer, possibly leading to a
47  *    crash.
48  *
49  * 4. A CFX wrap token with a plaintext EC value greater than the plaintext
50  *    length - 16 causes an integer underflow when computing the result length,
51  *    likely causing a crash.
52  *
53  * 5. An IOV unwrap operation will overrun the header buffer if an ASN.1
54  *    wrapper longer than the header buffer is present.
55  *
56  * 6. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
57  *    header causes an input buffer overrun, usually leading to either a segv
58  *    or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or
59  *    sequence number values.  This vulnerability also applies to IOV unwrap.
60  *
61  * 7. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
62  *    header causes an integer underflow when computing the ciphertext length,
63  *    leading to an allocation error on 32-bit platforms or a segv on 64-bit
64  *    platforms.  A pre-CFX MIC token of this size causes an input buffer
65  *    overrun when comparing the checksum, perhaps leading to a segv.
66  *
67  * 8. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
68  *    ciphertext (where padlen is the last byte of the decrypted ciphertext)
69  *    causes an integer underflow when computing the original message length,
70  *    leading to an allocation error.
71  *
72  * 9. In the mechglue, truncated encapsulation in the initial context token can
73  *    cause input buffer overruns in gss_accept_sec_context().
74  */
75 
76 #include "k5-int.h"
77 #include "common.h"
78 #include "mglueP.h"
79 #include "gssapiP_krb5.h"
80 
81 /*
82  * The following samples contain context parameters and otherwise valid seal
83  * tokens where the plain text is padded with byte value 100 instead of the
84  * proper value 1.
85  */
86 struct test {
87     krb5_enctype enctype;
88     krb5_enctype encseq_enctype;
89     int sealalg;
90     int signalg;
91     size_t cksum_size;
92     size_t keylen;
93     const char *keydata;
94     size_t toklen;
95     const char *token;
96 } tests[] = {
97     {
98         ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,
99         SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,
100         24,
101         "\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"
102         "\x92\x3D\x38\xF7\x26\x73\x0D\x6D",
103         65,
104         "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
105         "\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"
106         "\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"
107         "\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4"
108     },
109     {
110         ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,
111         SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,
112         16,
113         "\x66\x64\x41\x64\x55\x78\x21\xD0\xD0\xFD\x05\x6A\xFF\x6F\xE8\x09",
114         53,
115         "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
116         "\x00\x10\x00\xFF\xFF\x35\xD4\x79\xF3\x8C\x47\x8F\x6E\x23\x6F\x3E"
117         "\xCC\x5E\x57\x5C\x6A\x89\xF0\xA2\x03\x4F\x0B\x51\x11\xEE\x89\x7E"
118         "\xD6\xF6\xB5\xD6\x51"
119     }
120 };
121 
122 static void *
ealloc(size_t len)123 ealloc(size_t len)
124 {
125     void *ptr = calloc(len, 1);
126 
127     if (ptr == NULL)
128         abort();
129     return ptr;
130 }
131 
132 /* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.
133  * The context takes ownership of subkey. */
134 static gss_ctx_id_t
make_fake_cfx_context(krb5_key subkey)135 make_fake_cfx_context(krb5_key subkey)
136 {
137     gss_union_ctx_id_t uctx;
138     krb5_gss_ctx_id_t kgctx;
139 
140     kgctx = ealloc(sizeof(*kgctx));
141     kgctx->established = 1;
142     kgctx->proto = 1;
143     if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
144         abort();
145     kgctx->mech_used = &mech_krb5;
146     kgctx->sealalg = -1;
147     kgctx->signalg = -1;
148 
149     kgctx->subkey = subkey;
150     kgctx->cksumtype = CKSUMTYPE_HMAC_SHA1_96_AES128;
151 
152     uctx = ealloc(sizeof(*uctx));
153     uctx->mech_type = &mech_krb5;
154     uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
155     return (gss_ctx_id_t)uctx;
156 }
157 
158 /* Fake up enough of a GSS context for gss_unwrap, using keys from test. */
159 static gss_ctx_id_t
make_fake_context(const struct test * test)160 make_fake_context(const struct test *test)
161 {
162     gss_union_ctx_id_t uctx;
163     krb5_gss_ctx_id_t kgctx;
164     krb5_keyblock kb;
165 
166     kgctx = ealloc(sizeof(*kgctx));
167     kgctx->established = 1;
168     if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
169         abort();
170     kgctx->mech_used = &mech_krb5;
171     kgctx->sealalg = test->sealalg;
172     kgctx->signalg = test->signalg;
173     kgctx->cksum_size = test->cksum_size;
174 
175     kb.enctype = test->enctype;
176     kb.length = test->keylen;
177     kb.contents = (unsigned char *)test->keydata;
178     if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
179         abort();
180 
181     kb.enctype = test->encseq_enctype;
182     if (krb5_k_create_key(NULL, &kb, &kgctx->seq) != 0)
183         abort();
184 
185     if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
186         abort();
187 
188     uctx = ealloc(sizeof(*uctx));
189     uctx->mech_type = &mech_krb5;
190     uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
191     return (gss_ctx_id_t)uctx;
192 }
193 
194 /* Free a context created by make_fake_context. */
195 static void
free_fake_context(gss_ctx_id_t ctx)196 free_fake_context(gss_ctx_id_t ctx)
197 {
198     gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx;
199     krb5_gss_ctx_id_t kgctx = (krb5_gss_ctx_id_t)uctx->internal_ctx_id;
200 
201     free(kgctx->seqstate);
202     krb5_k_free_key(NULL, kgctx->subkey);
203     krb5_k_free_key(NULL, kgctx->seq);
204     krb5_k_free_key(NULL, kgctx->enc);
205     free(kgctx);
206     free(uctx);
207 }
208 
209 /* Prefix a token (starting at the two-byte ID) with an ASN.1 header and return
210  * it in an allocated block to facilitate checking by valgrind or similar. */
211 static void
make_token(unsigned char * token,size_t len,gss_buffer_t out)212 make_token(unsigned char *token, size_t len, gss_buffer_t out)
213 {
214     char *wrapped;
215 
216     assert(mech_krb5.length == 9);
217     assert(len + 11 < 128);
218     wrapped = ealloc(len + 13);
219     wrapped[0] = 0x60;
220     wrapped[1] = len + 11;
221     wrapped[2] = 0x06;
222     wrapped[3] = 9;
223     memcpy(wrapped + 4, mech_krb5.elements, 9);
224     memcpy(wrapped + 13, token, len);
225     out->length = len + 13;
226     out->value = wrapped;
227 }
228 
229 /* Create a 16-byte header for a CFX confidential wrap token to be processed by
230  * the fake CFX context. */
231 static void
write_cfx_header(uint16_t ec,uint8_t * out)232 write_cfx_header(uint16_t ec, uint8_t *out)
233 {
234     memset(out, 0, 16);
235     store_16_be(KG2_TOK_WRAP_MSG, out);
236     out[2] = FLAG_WRAP_CONFIDENTIAL;
237     out[3] = 0xFF;
238     store_16_be(ec, out + 4);
239 }
240 
241 /* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
242  * regular and IOV unwrap. */
243 static void
test_bogus_1964_token(gss_ctx_id_t ctx)244 test_bogus_1964_token(gss_ctx_id_t ctx)
245 {
246     OM_uint32 minor, major;
247     unsigned char tokbuf[128];
248     gss_buffer_desc in, out;
249     gss_iov_buffer_desc iov;
250 
251     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
252     store_16_le(SGN_ALG_HMAC_MD5, tokbuf + 2);
253     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
254     store_16_le(0xFFFF, tokbuf + 6);
255     memset(tokbuf + 8, 0, 16);
256     make_token(tokbuf, 24, &in);
257 
258     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
259     if (major != GSS_S_DEFECTIVE_TOKEN)
260         abort();
261     (void)gss_release_buffer(&minor, &out);
262 
263     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
264     iov.buffer = in;
265     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
266     if (major != GSS_S_DEFECTIVE_TOKEN)
267         abort();
268 
269     free(in.value);
270 }
271 
272 static void
test_cfx_altered_ec(gss_ctx_id_t ctx,krb5_key subkey)273 test_cfx_altered_ec(gss_ctx_id_t ctx, krb5_key subkey)
274 {
275     OM_uint32 major, minor;
276     uint8_t tokbuf[128], plainbuf[24];
277     krb5_data plain;
278     krb5_enc_data cipher;
279     gss_buffer_desc in, out;
280     gss_iov_buffer_desc iov[2];
281 
282     /* Construct a header with a plaintext EC value of 3. */
283     write_cfx_header(3, tokbuf);
284 
285     /* Encrypt a plaintext and a copy of the header with the EC value 0. */
286     memcpy(plainbuf, "truncate", 8);
287     memcpy(plainbuf + 8, tokbuf, 16);
288     store_16_be(0, plainbuf + 12);
289     plain = make_data(plainbuf, 24);
290     cipher.ciphertext.data = (char *)tokbuf + 16;
291     cipher.ciphertext.length = sizeof(tokbuf) - 16;
292     cipher.enctype = subkey->keyblock.enctype;
293     if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
294                        &plain, &cipher) != 0)
295         abort();
296 
297     /* Verify that the token is rejected by gss_unwrap(). */
298     in.value = tokbuf;
299     in.length = 16 + cipher.ciphertext.length;
300     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
301     if (major != GSS_S_DEFECTIVE_TOKEN)
302         abort();
303     (void)gss_release_buffer(&minor, &out);
304 
305     /* Verify that the token is rejected by gss_unwrap_iov(). */
306     iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
307     iov[0].buffer = in;
308     iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
309     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
310     if (major != GSS_S_DEFECTIVE_TOKEN)
311         abort();
312 }
313 
314 static void
test_cfx_short_plaintext(gss_ctx_id_t ctx,krb5_key subkey)315 test_cfx_short_plaintext(gss_ctx_id_t ctx, krb5_key subkey)
316 {
317     OM_uint32 major, minor;
318     uint8_t tokbuf[128], zerobyte = 0;
319     krb5_data plain;
320     krb5_enc_data cipher;
321     gss_buffer_desc in, out;
322 
323     write_cfx_header(0, tokbuf);
324 
325     /* Encrypt a single byte, with no copy of the header. */
326     plain = make_data(&zerobyte, 1);
327     cipher.ciphertext.data = (char *)tokbuf + 16;
328     cipher.ciphertext.length = sizeof(tokbuf) - 16;
329     cipher.enctype = subkey->keyblock.enctype;
330     if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
331                        &plain, &cipher) != 0)
332         abort();
333 
334     /* Verify that the token is rejected by gss_unwrap(). */
335     in.value = tokbuf;
336     in.length = 16 + cipher.ciphertext.length;
337     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
338     if (major != GSS_S_DEFECTIVE_TOKEN)
339         abort();
340     (void)gss_release_buffer(&minor, &out);
341 }
342 
343 static void
test_cfx_large_ec(gss_ctx_id_t ctx,krb5_key subkey)344 test_cfx_large_ec(gss_ctx_id_t ctx, krb5_key subkey)
345 {
346     OM_uint32 major, minor;
347     uint8_t tokbuf[128] = { 0 }, plainbuf[20];
348     krb5_data plain;
349     krb5_enc_data cipher;
350     gss_buffer_desc in, out;
351 
352     /* Construct a header with an EC value of 5. */
353     write_cfx_header(5, tokbuf);
354 
355     /* Encrypt a 4-byte plaintext plus the header. */
356     memcpy(plainbuf, "abcd", 4);
357     memcpy(plainbuf + 4, tokbuf, 16);
358     plain = make_data(plainbuf, 20);
359     cipher.ciphertext.data = (char *)tokbuf + 16;
360     cipher.ciphertext.length = sizeof(tokbuf) - 16;
361     cipher.enctype = subkey->keyblock.enctype;
362     if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
363                        &plain, &cipher) != 0)
364         abort();
365 
366     /* Verify that the token is rejected by gss_unwrap(). */
367     in.value = tokbuf;
368     in.length = 16 + cipher.ciphertext.length;
369     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
370     if (major != GSS_S_DEFECTIVE_TOKEN)
371         abort();
372     (void)gss_release_buffer(&minor, &out);
373 }
374 
375 static void
test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)376 test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)
377 {
378     OM_uint32 minor, major;
379     uint8_t databuf[10] = { 0 };
380     gss_iov_buffer_desc iov[2];
381 
382     /*
383      * In this IOV array, the header contains a DER tag with a dangling eight
384      * bytes of length field.  The data IOV indicates a total token length
385      * sufficient to contain the length bytes.
386      */
387     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
388     iov[0].buffer.value = ealloc(2);
389     iov[0].buffer.length = 2;
390     memcpy(iov[0].buffer.value, "\x60\x88", 2);
391     iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
392     iov[1].buffer.value = databuf;
393     iov[1].buffer.length = 10;
394     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
395     if (major != GSS_S_DEFECTIVE_TOKEN)
396         abort();
397     free(iov[0].buffer.value);
398 }
399 
400 /* Process wrap and MIC tokens with incomplete headers. */
401 static void
test_short_header(gss_ctx_id_t ctx)402 test_short_header(gss_ctx_id_t ctx)
403 {
404     OM_uint32 minor, major;
405     unsigned char tokbuf[128];
406     gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
407 
408     /* Seal token, 2-24 bytes */
409     store_16_be(KG_TOK_SEAL_MSG, tokbuf);
410     make_token(tokbuf, 2, &in);
411     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
412     if (major != GSS_S_DEFECTIVE_TOKEN)
413         abort();
414     free(in.value);
415     (void)gss_release_buffer(&minor, &out);
416 
417     /* Sign token, 2-24 bytes */
418     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
419     make_token(tokbuf, 2, &in);
420     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
421     if (major != GSS_S_DEFECTIVE_TOKEN)
422         abort();
423     free(in.value);
424     (void)gss_release_buffer(&minor, &out);
425 
426     /* MIC token, 2-24 bytes */
427     store_16_be(KG_TOK_MIC_MSG, tokbuf);
428     make_token(tokbuf, 2, &in);
429     major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
430     if (major != GSS_S_DEFECTIVE_TOKEN)
431         abort();
432     free(in.value);
433 }
434 
435 /* Process wrap and MIC tokens with incomplete headers. */
436 static void
test_short_header_iov(gss_ctx_id_t ctx,const struct test * test)437 test_short_header_iov(gss_ctx_id_t ctx, const struct test *test)
438 {
439     OM_uint32 minor, major;
440     unsigned char tokbuf[128];
441     gss_iov_buffer_desc iov;
442 
443     /* IOV seal token, 16-23 bytes */
444     store_16_be(KG_TOK_SEAL_MSG, tokbuf);
445     store_16_le(test->signalg, tokbuf + 2);
446     store_16_le(test->sealalg, tokbuf + 4);
447     store_16_be(0xFFFF, tokbuf + 6);
448     memset(tokbuf + 8, 0, 8);
449     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
450     make_token(tokbuf, 16, &iov.buffer);
451     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
452     if (major != GSS_S_DEFECTIVE_TOKEN)
453         abort();
454     free(iov.buffer.value);
455 
456     /* IOV sign token, 16-23 bytes */
457     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
458     store_16_le(test->signalg, tokbuf + 2);
459     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
460     store_16_le(0xFFFF, tokbuf + 6);
461     memset(tokbuf + 8, 0, 8);
462     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
463     make_token(tokbuf, 16, &iov.buffer);
464     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
465     if (major != GSS_S_DEFECTIVE_TOKEN)
466         abort();
467     free(iov.buffer.value);
468 
469     /* IOV MIC token, 16-23 bytes */
470     store_16_be(KG_TOK_MIC_MSG, tokbuf);
471     store_16_be(test->signalg, tokbuf + 2);
472     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
473     store_16_le(0xFFFF, tokbuf + 6);
474     memset(tokbuf + 8, 0, 8);
475     iov.type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
476     make_token(tokbuf, 16, &iov.buffer);
477     major = gss_verify_mic_iov(&minor, ctx, NULL, &iov, 1);
478     if (major != GSS_S_DEFECTIVE_TOKEN)
479         abort();
480     free(iov.buffer.value);
481 }
482 
483 /* Process wrap and MIC tokens with incomplete checksums. */
484 static void
test_short_checksum(gss_ctx_id_t ctx,const struct test * test)485 test_short_checksum(gss_ctx_id_t ctx, const struct test *test)
486 {
487     OM_uint32 minor, major;
488     unsigned char tokbuf[128];
489     gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
490 
491     /* Can only do this with the DES3 checksum, as we can't easily get past
492      * retrieving the sequence number when the checksum is only eight bytes. */
493     if (test->cksum_size <= 8)
494         return;
495     /* Seal token, fewer than 16 + cksum_size bytes.  Use the token from the
496      * test data to get a valid sequence number. */
497     make_token((unsigned char *)test->token + 13, 24, &in);
498     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
499     if (major != GSS_S_DEFECTIVE_TOKEN)
500         abort();
501     free(in.value);
502     (void)gss_release_buffer(&minor, &out);
503 
504     /* Sign token, fewer than 16 + cksum_size bytes. */
505     memcpy(tokbuf, test->token + 13, 24);
506     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
507     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
508     make_token(tokbuf, 24, &in);
509     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
510     if (major != GSS_S_DEFECTIVE_TOKEN)
511         abort();
512     free(in.value);
513     (void)gss_release_buffer(&minor, &out);
514 
515     /* MIC token, fewer than 16 + cksum_size bytes. */
516     memcpy(tokbuf, test->token + 13, 24);
517     store_16_be(KG_TOK_MIC_MSG, tokbuf);
518     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
519     make_token(tokbuf, 24, &in);
520     major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
521     if (major != GSS_S_DEFECTIVE_TOKEN)
522         abort();
523     free(in.value);
524 }
525 
526 /* Unwrap a token with a bogus padding byte in the decrypted ciphertext. */
527 static void
test_bad_pad(gss_ctx_id_t ctx,const struct test * test)528 test_bad_pad(gss_ctx_id_t ctx, const struct test *test)
529 {
530     OM_uint32 minor, major;
531     gss_buffer_desc in, out;
532 
533     in.length = test->toklen;
534     in.value = (char *)test->token;
535     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
536     if (major != GSS_S_BAD_SIG)
537         abort();
538     (void)gss_release_buffer(&minor, &out);
539 }
540 
541 static void
try_accept(void * value,size_t len)542 try_accept(void *value, size_t len)
543 {
544     OM_uint32 minor;
545     gss_buffer_desc in, out;
546     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
547 
548     /* Copy the provided value to make input overruns more obvious. */
549     in.value = ealloc(len);
550     memcpy(in.value, value, len);
551     in.length = len;
552     (void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
553                                  GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
554                                  &out, NULL, NULL, NULL);
555     gss_release_buffer(&minor, &out);
556     gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
557     free(in.value);
558 }
559 
560 /* Accept contexts using superficially valid but truncated encapsulations. */
561 static void
test_short_encapsulation()562 test_short_encapsulation()
563 {
564     /* Include just the initial application tag, to see if we overrun reading
565      * the sequence length. */
566     try_accept("\x60", 1);
567 
568     /* Indicate four additional sequence length bytes, to see if we overrun
569      * reading them (or skipping them and reading the next byte). */
570     try_accept("\x60\x84", 2);
571 
572     /* Include an object identifier tag but no length, to see if we overrun
573      * reading the length. */
574     try_accept("\x60\x40\x06", 3);
575 
576     /* Include an object identifier tag with a length matching the krb5 mech,
577      * but no OID bytes, to see if we overrun comparing against mechs. */
578     try_accept("\x60\x40\x06\x09", 4);
579 }
580 
581 int
main(int argc,char ** argv)582 main(int argc, char **argv)
583 {
584     krb5_keyblock kb;
585     krb5_key cfx_subkey;
586     gss_ctx_id_t ctx;
587     size_t i;
588 
589     kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
590     kb.length = 16;
591     kb.contents = (unsigned char *)"1234567887654321";
592     if (krb5_k_create_key(NULL, &kb, &cfx_subkey) != 0)
593         abort();
594 
595     ctx = make_fake_cfx_context(cfx_subkey);
596     test_bogus_1964_token(ctx);
597     test_cfx_altered_ec(ctx, cfx_subkey);
598     test_cfx_short_plaintext(ctx, cfx_subkey);
599     test_cfx_large_ec(ctx, cfx_subkey);
600     test_iov_large_asn1_wrapper(ctx);
601     free_fake_context(ctx);
602 
603     for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
604         ctx = make_fake_context(&tests[i]);
605         test_short_header(ctx);
606         test_short_header_iov(ctx, &tests[i]);
607         test_short_checksum(ctx, &tests[i]);
608         test_bad_pad(ctx, &tests[i]);
609         free_fake_context(ctx);
610     }
611 
612     test_short_encapsulation();
613 
614     return 0;
615 }
616