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