Fix autoconf 2.70 compatibility
[platform/upstream/krb5.git] / src / tests / gssapi / t_invalid.c
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.)
40  *
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.
45  *
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.
51  *
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.
56  *
57  * 5. In the mechglue, truncated encapsulation in the initial context token can
58  *    cause input buffer overruns in gss_accept_sec_context().
59  *
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.
64  */
65
66 #include "k5-int.h"
67 #include "common.h"
68 #include "mglueP.h"
69 #include "gssapiP_krb5.h"
70
71 /*
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
74  * proper value 1.
75  */
76 struct test {
77     krb5_enctype enctype;
78     krb5_enctype encseq_enctype;
79     int sealalg;
80     int signalg;
81     size_t cksum_size;
82     size_t keylen;
83     const char *keydata;
84     size_t toklen;
85     const char *token;
86 } tests[] = {
87     {
88         ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_RAW,
89         SEAL_ALG_DES, SGN_ALG_DES_MAC_MD5, 8,
90         8,
91         "\x26\xEC\xBA\xB6\xFE\xBA\x91\xCE",
92         53,
93         "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x00"
94         "\x00\x00\x00\xFF\xFF\xF0\x0B\x90\x7B\xC4\xFC\xEB\xF4\x84\x9C\x5A"
95         "\xA8\x56\x41\x3E\xE1\x62\xEE\x38\xD1\x34\x9A\xE3\xFB\xC9\xFD\x0A"
96         "\xDC\x83\xE1\x4A\xE4"
97     },
98     {
99         ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,
100         SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,
101         24,
102         "\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"
103         "\x92\x3D\x38\xF7\x26\x73\x0D\x6D",
104         65,
105         "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
106         "\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"
107         "\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"
108         "\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4"
109     },
110     {
111         ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,
112         SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,
113         16,
114         "\x66\x64\x41\x64\x55\x78\x21\xD0\xD0\xFD\x05\x6A\xFF\x6F\xE8\x09",
115         53,
116         "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
117         "\x00\x10\x00\xFF\xFF\x35\xD4\x79\xF3\x8C\x47\x8F\x6E\x23\x6F\x3E"
118         "\xCC\x5E\x57\x5C\x6A\x89\xF0\xA2\x03\x4F\x0B\x51\x11\xEE\x89\x7E"
119         "\xD6\xF6\xB5\xD6\x51"
120     }
121 };
122
123 /* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */
124 static gss_ctx_id_t
125 make_fake_cfx_context()
126 {
127     gss_union_ctx_id_t uctx;
128     krb5_gss_ctx_id_t kgctx;
129     krb5_keyblock kb;
130
131     kgctx = calloc(1, sizeof(*kgctx));
132     if (kgctx == NULL)
133         abort();
134     kgctx->established = 1;
135     kgctx->proto = 1;
136     if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
137         abort();
138     kgctx->mech_used = &mech_krb5;
139     kgctx->sealalg = -1;
140     kgctx->signalg = -1;
141
142     kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
143     kb.length = 16;
144     kb.contents = (unsigned char *)"1234567887654321";
145     if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
146         abort();
147
148     uctx = calloc(1, sizeof(*uctx));
149     if (uctx == NULL)
150         abort();
151     uctx->mech_type = &mech_krb5;
152     uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
153     return (gss_ctx_id_t)uctx;
154 }
155
156 /* Fake up enough of a GSS context for gss_unwrap, using keys from test. */
157 static gss_ctx_id_t
158 make_fake_context(const struct test *test)
159 {
160     gss_union_ctx_id_t uctx;
161     krb5_gss_ctx_id_t kgctx;
162     krb5_keyblock kb;
163     unsigned char encbuf[8];
164     size_t i;
165
166     kgctx = calloc(1, sizeof(*kgctx));
167     if (kgctx == NULL)
168         abort();
169     kgctx->established = 1;
170     if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
171         abort();
172     kgctx->mech_used = &mech_krb5;
173     kgctx->sealalg = test->sealalg;
174     kgctx->signalg = test->signalg;
175     kgctx->cksum_size = test->cksum_size;
176
177     kb.enctype = test->enctype;
178     kb.length = test->keylen;
179     kb.contents = (unsigned char *)test->keydata;
180     if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
181         abort();
182
183     kb.enctype = test->encseq_enctype;
184     if (krb5_k_create_key(NULL, &kb, &kgctx->seq) != 0)
185         abort();
186
187     if (kb.enctype == ENCTYPE_DES_CBC_RAW) {
188         for (i = 0; i < 8; i++)
189             encbuf[i] = kb.contents[i] ^ 0xF0;
190         kb.contents = encbuf;
191     }
192     if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
193         abort();
194
195     uctx = calloc(1, sizeof(*uctx));
196     if (uctx == NULL)
197         abort();
198     uctx->mech_type = &mech_krb5;
199     uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
200     return (gss_ctx_id_t)uctx;
201 }
202
203 /* Free a context created by make_fake_context. */
204 static void
205 free_fake_context(gss_ctx_id_t ctx)
206 {
207     gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx;
208     krb5_gss_ctx_id_t kgctx = (krb5_gss_ctx_id_t)uctx->internal_ctx_id;
209
210     free(kgctx->seqstate);
211     krb5_k_free_key(NULL, kgctx->subkey);
212     krb5_k_free_key(NULL, kgctx->seq);
213     krb5_k_free_key(NULL, kgctx->enc);
214     free(kgctx);
215     free(uctx);
216 }
217
218 /* Prefix a token (starting at the two-byte ID) with an ASN.1 header and return
219  * it in an allocated block to facilitate checking by valgrind or similar. */
220 static void
221 make_token(unsigned char *token, size_t len, gss_buffer_t out)
222 {
223     char *wrapped;
224
225     assert(mech_krb5.length == 9);
226     assert(len + 11 < 128);
227     wrapped = malloc(len + 13);
228     if (wrapped == NULL)
229         abort();
230     wrapped[0] = 0x60;
231     wrapped[1] = len + 11;
232     wrapped[2] = 0x06;
233     wrapped[3] = 9;
234     memcpy(wrapped + 4, mech_krb5.elements, 9);
235     memcpy(wrapped + 13, token, len);
236     out->length = len + 13;
237     out->value = wrapped;
238 }
239
240 /* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
241  * regular and IOV unwrap. */
242 static void
243 test_bogus_1964_token(gss_ctx_id_t ctx)
244 {
245     OM_uint32 minor, major;
246     unsigned char tokbuf[128];
247     gss_buffer_desc in, out;
248     gss_iov_buffer_desc iov;
249
250     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
251     store_16_le(SGN_ALG_DES_MAC_MD5, tokbuf + 2);
252     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
253     store_16_le(0xFFFF, tokbuf + 6);
254     memset(tokbuf + 8, 0, 16);
255     make_token(tokbuf, 24, &in);
256
257     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
258     if (major != GSS_S_DEFECTIVE_TOKEN)
259         abort();
260     (void)gss_release_buffer(&minor, &out);
261
262     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
263     iov.buffer = in;
264     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
265     if (major != GSS_S_DEFECTIVE_TOKEN)
266         abort();
267
268     free(in.value);
269 }
270
271 /* Process wrap and MIC tokens with incomplete headers. */
272 static void
273 test_short_header(gss_ctx_id_t ctx)
274 {
275     OM_uint32 minor, major;
276     unsigned char tokbuf[128];
277     gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
278
279     /* Seal token, 2-24 bytes */
280     store_16_be(KG_TOK_SEAL_MSG, tokbuf);
281     make_token(tokbuf, 2, &in);
282     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
283     if (major != GSS_S_DEFECTIVE_TOKEN)
284         abort();
285     free(in.value);
286     (void)gss_release_buffer(&minor, &out);
287
288     /* Sign token, 2-24 bytes */
289     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
290     make_token(tokbuf, 2, &in);
291     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
292     if (major != GSS_S_DEFECTIVE_TOKEN)
293         abort();
294     free(in.value);
295     (void)gss_release_buffer(&minor, &out);
296
297     /* MIC token, 2-24 bytes */
298     store_16_be(KG_TOK_MIC_MSG, tokbuf);
299     make_token(tokbuf, 2, &in);
300     major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
301     if (major != GSS_S_DEFECTIVE_TOKEN)
302         abort();
303     free(in.value);
304 }
305
306 /* Process wrap and MIC tokens with incomplete headers. */
307 static void
308 test_short_header_iov(gss_ctx_id_t ctx, const struct test *test)
309 {
310     OM_uint32 minor, major;
311     unsigned char tokbuf[128];
312     gss_iov_buffer_desc iov;
313
314     /* IOV seal token, 16-23 bytes */
315     store_16_be(KG_TOK_SEAL_MSG, tokbuf);
316     store_16_le(test->signalg, tokbuf + 2);
317     store_16_le(test->sealalg, tokbuf + 4);
318     store_16_be(0xFFFF, tokbuf + 6);
319     memset(tokbuf + 8, 0, 8);
320     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
321     make_token(tokbuf, 16, &iov.buffer);
322     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
323     if (major != GSS_S_DEFECTIVE_TOKEN)
324         abort();
325     free(iov.buffer.value);
326
327     /* IOV sign token, 16-23 bytes */
328     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
329     store_16_le(test->signalg, tokbuf + 2);
330     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
331     store_16_le(0xFFFF, tokbuf + 6);
332     memset(tokbuf + 8, 0, 8);
333     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
334     make_token(tokbuf, 16, &iov.buffer);
335     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
336     if (major != GSS_S_DEFECTIVE_TOKEN)
337         abort();
338     free(iov.buffer.value);
339
340     /* IOV MIC token, 16-23 bytes */
341     store_16_be(KG_TOK_MIC_MSG, tokbuf);
342     store_16_be(test->signalg, tokbuf + 2);
343     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
344     store_16_le(0xFFFF, tokbuf + 6);
345     memset(tokbuf + 8, 0, 8);
346     iov.type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
347     make_token(tokbuf, 16, &iov.buffer);
348     major = gss_verify_mic_iov(&minor, ctx, NULL, &iov, 1);
349     if (major != GSS_S_DEFECTIVE_TOKEN)
350         abort();
351     free(iov.buffer.value);
352 }
353
354 /* Process wrap and MIC tokens with incomplete checksums. */
355 static void
356 test_short_checksum(gss_ctx_id_t ctx, const struct test *test)
357 {
358     OM_uint32 minor, major;
359     unsigned char tokbuf[128];
360     gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
361
362     /* Can only do this with the DES3 checksum, as we can't easily get past
363      * retrieving the sequence number when the checksum is only eight bytes. */
364     if (test->cksum_size <= 8)
365         return;
366     /* Seal token, fewer than 16 + cksum_size bytes.  Use the token from the
367      * test data to get a valid sequence number. */
368     make_token((unsigned char *)test->token + 13, 24, &in);
369     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
370     if (major != GSS_S_DEFECTIVE_TOKEN)
371         abort();
372     free(in.value);
373     (void)gss_release_buffer(&minor, &out);
374
375     /* Sign token, fewer than 16 + cksum_size bytes. */
376     memcpy(tokbuf, test->token + 13, 24);
377     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
378     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
379     make_token(tokbuf, 24, &in);
380     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
381     if (major != GSS_S_DEFECTIVE_TOKEN)
382         abort();
383     free(in.value);
384     (void)gss_release_buffer(&minor, &out);
385
386     /* MIC token, fewer than 16 + cksum_size bytes. */
387     memcpy(tokbuf, test->token + 13, 24);
388     store_16_be(KG_TOK_MIC_MSG, tokbuf);
389     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
390     make_token(tokbuf, 24, &in);
391     major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
392     if (major != GSS_S_DEFECTIVE_TOKEN)
393         abort();
394     free(in.value);
395 }
396
397 /* Unwrap a token with a bogus padding byte in the decrypted ciphertext. */
398 static void
399 test_bad_pad(gss_ctx_id_t ctx, const struct test *test)
400 {
401     OM_uint32 minor, major;
402     gss_buffer_desc in, out;
403
404     in.length = test->toklen;
405     in.value = (char *)test->token;
406     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
407     if (major != GSS_S_BAD_SIG)
408         abort();
409     (void)gss_release_buffer(&minor, &out);
410 }
411
412 static void
413 try_accept(void *value, size_t len)
414 {
415     OM_uint32 minor;
416     gss_buffer_desc in, out;
417     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
418
419     /* Copy the provided value to make input overruns more obvious. */
420     in.value = malloc(len);
421     if (in.value == NULL)
422         abort();
423     memcpy(in.value, value, len);
424     in.length = len;
425     (void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
426                                  GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
427                                  &out, NULL, NULL, NULL);
428     gss_release_buffer(&minor, &out);
429     gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
430     free(in.value);
431 }
432
433 /* Accept contexts using superficially valid but truncated encapsulations. */
434 static void
435 test_short_encapsulation()
436 {
437     /* Include just the initial application tag, to see if we overrun reading
438      * the sequence length. */
439     try_accept("\x60", 1);
440
441     /* Indicate four additional sequence length bytes, to see if we overrun
442      * reading them (or skipping them and reading the next byte). */
443     try_accept("\x60\x84", 2);
444
445     /* Include an object identifier tag but no length, to see if we overrun
446      * reading the length. */
447     try_accept("\x60\x40\x06", 3);
448
449     /* Include an object identifier tag with a length matching the krb5 mech,
450      * but no OID bytes, to see if we overrun comparing against mechs. */
451     try_accept("\x60\x40\x06\x09", 4);
452 }
453
454 int
455 main(int argc, char **argv)
456 {
457     gss_ctx_id_t ctx;
458     size_t i;
459
460     ctx = make_fake_cfx_context();
461     test_bogus_1964_token(ctx);
462     free_fake_context(ctx);
463
464     for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
465         ctx = make_fake_context(&tests[i]);
466         test_short_header(ctx);
467         test_short_header_iov(ctx, &tests[i]);
468         test_short_checksum(ctx, &tests[i]);
469         test_bad_pad(ctx, &tests[i]);
470         free_fake_context(ctx);
471     }
472
473     test_short_encapsulation();
474
475     return 0;
476 }