1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/gssapi/t_invalid.c - Invalid message token regression tests */
4 * Copyright (C) 2014 by the Massachusetts Institute of Technology.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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.
34 * This file contains regression tests for some GSSAPI invalid token
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
41 * 2. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
42 * header causes an input buffer overrun, usually leading to either a segv
43 * or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or
44 * sequence number values.
46 * 3. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
47 * header causes an integer underflow when computing the ciphertext length,
48 * leading to an allocation error on 32-bit platforms or a segv on 64-bit
49 * platforms. A pre-CFX MIC token of this size causes an input buffer
50 * overrun when comparing the checksum, perhaps leading to a segv.
52 * 4. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
53 * ciphertext (where padlen is the last byte of the decrypted ciphertext)
54 * causes an integer underflow when computing the original message length,
55 * leading to an allocation error.
57 * 5. In the mechglue, truncated encapsulation in the initial context token can
58 * cause input buffer overruns in gss_accept_sec_context().
60 * Vulnerabilities #1 and #2 also apply to IOV unwrap, although tokens with
61 * fewer than 16 bytes after the ASN.1 header will be rejected.
62 * Vulnerabilities #2 and #5 can only be robustly detected using a
63 * memory-checking environment such as valgrind.
69 #include "gssapiP_krb5.h"
72 * The following samples contain context parameters and otherwise valid seal
73 * tokens where the plain text is padded with byte value 100 instead of the
78 krb5_enctype encseq_enctype;
88 ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,
89 SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,
91 "\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"
92 "\x92\x3D\x38\xF7\x26\x73\x0D\x6D",
94 "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
95 "\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"
96 "\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"
97 "\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4"
100 ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,
101 SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,
103 "\x66\x64\x41\x64\x55\x78\x21\xD0\xD0\xFD\x05\x6A\xFF\x6F\xE8\x09",
105 "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
106 "\x00\x10\x00\xFF\xFF\x35\xD4\x79\xF3\x8C\x47\x8F\x6E\x23\x6F\x3E"
107 "\xCC\x5E\x57\x5C\x6A\x89\xF0\xA2\x03\x4F\x0B\x51\x11\xEE\x89\x7E"
108 "\xD6\xF6\xB5\xD6\x51"
112 /* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */
114 make_fake_cfx_context()
116 gss_union_ctx_id_t uctx;
117 krb5_gss_ctx_id_t kgctx;
120 kgctx = calloc(1, sizeof(*kgctx));
123 kgctx->established = 1;
125 if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
127 kgctx->mech_used = &mech_krb5;
131 kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
133 kb.contents = (unsigned char *)"1234567887654321";
134 if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
137 uctx = calloc(1, sizeof(*uctx));
140 uctx->mech_type = &mech_krb5;
141 uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
142 return (gss_ctx_id_t)uctx;
145 /* Fake up enough of a GSS context for gss_unwrap, using keys from test. */
147 make_fake_context(const struct test *test)
149 gss_union_ctx_id_t uctx;
150 krb5_gss_ctx_id_t kgctx;
153 kgctx = calloc(1, sizeof(*kgctx));
156 kgctx->established = 1;
157 if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
159 kgctx->mech_used = &mech_krb5;
160 kgctx->sealalg = test->sealalg;
161 kgctx->signalg = test->signalg;
162 kgctx->cksum_size = test->cksum_size;
164 kb.enctype = test->enctype;
165 kb.length = test->keylen;
166 kb.contents = (unsigned char *)test->keydata;
167 if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
170 kb.enctype = test->encseq_enctype;
171 if (krb5_k_create_key(NULL, &kb, &kgctx->seq) != 0)
174 if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
177 uctx = calloc(1, sizeof(*uctx));
180 uctx->mech_type = &mech_krb5;
181 uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
182 return (gss_ctx_id_t)uctx;
185 /* Free a context created by make_fake_context. */
187 free_fake_context(gss_ctx_id_t ctx)
189 gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx;
190 krb5_gss_ctx_id_t kgctx = (krb5_gss_ctx_id_t)uctx->internal_ctx_id;
192 free(kgctx->seqstate);
193 krb5_k_free_key(NULL, kgctx->subkey);
194 krb5_k_free_key(NULL, kgctx->seq);
195 krb5_k_free_key(NULL, kgctx->enc);
200 /* Prefix a token (starting at the two-byte ID) with an ASN.1 header and return
201 * it in an allocated block to facilitate checking by valgrind or similar. */
203 make_token(unsigned char *token, size_t len, gss_buffer_t out)
207 assert(mech_krb5.length == 9);
208 assert(len + 11 < 128);
209 wrapped = malloc(len + 13);
213 wrapped[1] = len + 11;
216 memcpy(wrapped + 4, mech_krb5.elements, 9);
217 memcpy(wrapped + 13, token, len);
218 out->length = len + 13;
219 out->value = wrapped;
222 /* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
223 * regular and IOV unwrap. */
225 test_bogus_1964_token(gss_ctx_id_t ctx)
227 OM_uint32 minor, major;
228 unsigned char tokbuf[128];
229 gss_buffer_desc in, out;
230 gss_iov_buffer_desc iov;
232 store_16_be(KG_TOK_SIGN_MSG, tokbuf);
233 store_16_le(SGN_ALG_HMAC_MD5, tokbuf + 2);
234 store_16_le(SEAL_ALG_NONE, tokbuf + 4);
235 store_16_le(0xFFFF, tokbuf + 6);
236 memset(tokbuf + 8, 0, 16);
237 make_token(tokbuf, 24, &in);
239 major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
240 if (major != GSS_S_DEFECTIVE_TOKEN)
242 (void)gss_release_buffer(&minor, &out);
244 iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
246 major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
247 if (major != GSS_S_DEFECTIVE_TOKEN)
253 /* Process wrap and MIC tokens with incomplete headers. */
255 test_short_header(gss_ctx_id_t ctx)
257 OM_uint32 minor, major;
258 unsigned char tokbuf[128];
259 gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
261 /* Seal token, 2-24 bytes */
262 store_16_be(KG_TOK_SEAL_MSG, tokbuf);
263 make_token(tokbuf, 2, &in);
264 major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
265 if (major != GSS_S_DEFECTIVE_TOKEN)
268 (void)gss_release_buffer(&minor, &out);
270 /* Sign token, 2-24 bytes */
271 store_16_be(KG_TOK_SIGN_MSG, tokbuf);
272 make_token(tokbuf, 2, &in);
273 major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
274 if (major != GSS_S_DEFECTIVE_TOKEN)
277 (void)gss_release_buffer(&minor, &out);
279 /* MIC token, 2-24 bytes */
280 store_16_be(KG_TOK_MIC_MSG, tokbuf);
281 make_token(tokbuf, 2, &in);
282 major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
283 if (major != GSS_S_DEFECTIVE_TOKEN)
288 /* Process wrap and MIC tokens with incomplete headers. */
290 test_short_header_iov(gss_ctx_id_t ctx, const struct test *test)
292 OM_uint32 minor, major;
293 unsigned char tokbuf[128];
294 gss_iov_buffer_desc iov;
296 /* IOV seal token, 16-23 bytes */
297 store_16_be(KG_TOK_SEAL_MSG, tokbuf);
298 store_16_le(test->signalg, tokbuf + 2);
299 store_16_le(test->sealalg, tokbuf + 4);
300 store_16_be(0xFFFF, tokbuf + 6);
301 memset(tokbuf + 8, 0, 8);
302 iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
303 make_token(tokbuf, 16, &iov.buffer);
304 major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
305 if (major != GSS_S_DEFECTIVE_TOKEN)
307 free(iov.buffer.value);
309 /* IOV sign token, 16-23 bytes */
310 store_16_be(KG_TOK_SIGN_MSG, tokbuf);
311 store_16_le(test->signalg, tokbuf + 2);
312 store_16_le(SEAL_ALG_NONE, tokbuf + 4);
313 store_16_le(0xFFFF, tokbuf + 6);
314 memset(tokbuf + 8, 0, 8);
315 iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
316 make_token(tokbuf, 16, &iov.buffer);
317 major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
318 if (major != GSS_S_DEFECTIVE_TOKEN)
320 free(iov.buffer.value);
322 /* IOV MIC token, 16-23 bytes */
323 store_16_be(KG_TOK_MIC_MSG, tokbuf);
324 store_16_be(test->signalg, tokbuf + 2);
325 store_16_le(SEAL_ALG_NONE, tokbuf + 4);
326 store_16_le(0xFFFF, tokbuf + 6);
327 memset(tokbuf + 8, 0, 8);
328 iov.type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
329 make_token(tokbuf, 16, &iov.buffer);
330 major = gss_verify_mic_iov(&minor, ctx, NULL, &iov, 1);
331 if (major != GSS_S_DEFECTIVE_TOKEN)
333 free(iov.buffer.value);
336 /* Process wrap and MIC tokens with incomplete checksums. */
338 test_short_checksum(gss_ctx_id_t ctx, const struct test *test)
340 OM_uint32 minor, major;
341 unsigned char tokbuf[128];
342 gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
344 /* Can only do this with the DES3 checksum, as we can't easily get past
345 * retrieving the sequence number when the checksum is only eight bytes. */
346 if (test->cksum_size <= 8)
348 /* Seal token, fewer than 16 + cksum_size bytes. Use the token from the
349 * test data to get a valid sequence number. */
350 make_token((unsigned char *)test->token + 13, 24, &in);
351 major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
352 if (major != GSS_S_DEFECTIVE_TOKEN)
355 (void)gss_release_buffer(&minor, &out);
357 /* Sign token, fewer than 16 + cksum_size bytes. */
358 memcpy(tokbuf, test->token + 13, 24);
359 store_16_be(KG_TOK_SIGN_MSG, tokbuf);
360 store_16_le(SEAL_ALG_NONE, tokbuf + 4);
361 make_token(tokbuf, 24, &in);
362 major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
363 if (major != GSS_S_DEFECTIVE_TOKEN)
366 (void)gss_release_buffer(&minor, &out);
368 /* MIC token, fewer than 16 + cksum_size bytes. */
369 memcpy(tokbuf, test->token + 13, 24);
370 store_16_be(KG_TOK_MIC_MSG, tokbuf);
371 store_16_le(SEAL_ALG_NONE, tokbuf + 4);
372 make_token(tokbuf, 24, &in);
373 major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
374 if (major != GSS_S_DEFECTIVE_TOKEN)
379 /* Unwrap a token with a bogus padding byte in the decrypted ciphertext. */
381 test_bad_pad(gss_ctx_id_t ctx, const struct test *test)
383 OM_uint32 minor, major;
384 gss_buffer_desc in, out;
386 in.length = test->toklen;
387 in.value = (char *)test->token;
388 major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
389 if (major != GSS_S_BAD_SIG)
391 (void)gss_release_buffer(&minor, &out);
395 try_accept(void *value, size_t len)
398 gss_buffer_desc in, out;
399 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
401 /* Copy the provided value to make input overruns more obvious. */
402 in.value = malloc(len);
403 if (in.value == NULL)
405 memcpy(in.value, value, len);
407 (void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
408 GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
409 &out, NULL, NULL, NULL);
410 gss_release_buffer(&minor, &out);
411 gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
415 /* Accept contexts using superficially valid but truncated encapsulations. */
417 test_short_encapsulation()
419 /* Include just the initial application tag, to see if we overrun reading
420 * the sequence length. */
421 try_accept("\x60", 1);
423 /* Indicate four additional sequence length bytes, to see if we overrun
424 * reading them (or skipping them and reading the next byte). */
425 try_accept("\x60\x84", 2);
427 /* Include an object identifier tag but no length, to see if we overrun
428 * reading the length. */
429 try_accept("\x60\x40\x06", 3);
431 /* Include an object identifier tag with a length matching the krb5 mech,
432 * but no OID bytes, to see if we overrun comparing against mechs. */
433 try_accept("\x60\x40\x06\x09", 4);
437 main(int argc, char **argv)
442 ctx = make_fake_cfx_context();
443 test_bogus_1964_token(ctx);
444 free_fake_context(ctx);
446 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
447 ctx = make_fake_context(&tests[i]);
448 test_short_header(ctx);
449 test_short_header_iov(ctx, &tests[i]);
450 test_short_checksum(ctx, &tests[i]);
451 test_bad_pad(ctx, &tests[i]);
452 free_fake_context(ctx);
455 test_short_encapsulation();