xref: /freebsd/crypto/krb5/src/tests/gssapi/t_invalid.c (revision 621e0e7f27303452c2f5b5fcf93aaf72e2b036a6)
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:
83  * - context parameters
84  * - otherwise valid seal tokens where the plain text is padded with byte value
85  *   100 instead of the proper value 1.
86  * - valid MIC tokens for the message "message"
87  * - two valid wrap tokens for the message "message", one without
88  *   confidentiality and one with
89  */
90 struct test {
91     krb5_enctype enctype;
92     krb5_enctype encseq_enctype;
93     int sealalg;
94     int signalg;
95     size_t cksum_size;
96     size_t keylen;
97     const char *keydata;
98     size_t toklen;
99     const char *token;
100     size_t miclen;
101     const char *mic;
102     size_t wrap1len;
103     const char *wrap1;
104     size_t wrap2len;
105     const char *wrap2;
106 } tests[] = {
107     {
108         ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,
109         SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,
110         24,
111         "\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"
112         "\x92\x3D\x38\xF7\x26\x73\x0D\x6D",
113         65,
114         "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
115         "\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"
116         "\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"
117         "\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4",
118         49,
119         "\x60\x2F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01\x01\x04"
120         "\x00\xFF\xFF\xFF\xFF\x57\xF5\x77\xC6\xC0\x72\x26\x97\x00\x89\xB2"
121         "\xEE\xD9\xD1\x90\xE7\x11\x50\x4F\xE9\x59\x18\xB1\x8F\x82\x8E\x8F\x5E",
122         65,
123         "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
124         "\x00\xFF\xFF\xFF\xFF\x0B\x81\x56\x4A\x02\x1B\xBE\x83\x2B\x35\x08"
125         "\x7B\x49\x15\x07\x97\x6A\x64\xEF\xDD\x32\x52\xF0\xA2\xE2\x62\x9B"
126         "\xA7\x72\xF7\x3D\x6B\x2D\xAC\x21\xE9\x6D\x65\x73\x73\x61\x67\x65\x01",
127         65,
128         "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
129         "\x00\x02\x00\xFF\xFF\x66\x5A\xE1\xC8\x4F\x69\x33\x97\x5D\x05\xE2"
130         "\x86\x40\x14\x15\x14\x27\x01\x9F\x32\x9D\x82\xF4\xE1\xC5\x3E\xFA"
131         "\x6D\x7D\x05\x39\xAE\x21\x44\xA0\x87\xA6\x24\xED\xFC\xA3\x53\xF1\x30"
132     },
133     {
134         ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,
135         SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,
136         16,
137         "\x66\x64\x41\x64\x55\x78\x21\xD0\xD0\xFD\x05\x6A\xFF\x6F\xE8\x09",
138         53,
139         "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
140         "\x00\x10\x00\xFF\xFF\x35\xD4\x79\xF3\x8C\x47\x8F\x6E\x23\x6F\x3E"
141         "\xCC\x5E\x57\x5C\x6A\x89\xF0\xA2\x03\x4F\x0B\x51\x11\xEE\x89\x7E"
142         "\xD6\xF6\xB5\xD6\x51",
143         37,
144         "\x60\x23\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01\x01\x11"
145         "\x00\xFF\xFF\xFF\xFF\x5D\xE7\x51\xF6\xFB\x6C\x25\x5B\x23\x93\x5A"
146         "\x30\x20\x57\xDC\xB5",
147         53,
148         "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
149         "\x00\xFF\xFF\xFF\xFF\xAD\xB5\x1D\x01\x39\x7B\xA2\x16\x4C\x1B\x68"
150         "\x18\xEC\xAC\xD9\xE5\x9E\xD1\x41\x7A\x89\xE8\xCB\x24\x6D\x65\x73"
151         "\x73\x61\x67\x65\x01",
152         53,
153         "\x60\x33\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x11"
154         "\x00\x10\x00\xFF\xFF\xDD\x6D\x04\xEA\x64\x5C\xE7\x31\x50\xD0\x09"
155         "\x44\x9E\x67\xA4\x30\xEC\xFB\xFF\xC0\xF7\x16\x1E\x14\x1A\x82\x42"
156         "\xDD\x26\x23\x2B\x02"
157     }
158 };
159 
160 static void *
ealloc(size_t len)161 ealloc(size_t len)
162 {
163     void *ptr = calloc(len, 1);
164 
165     if (ptr == NULL)
166         abort();
167     return ptr;
168 }
169 
170 /* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.
171  * The context takes ownership of subkey. */
172 static gss_ctx_id_t
make_fake_cfx_context(krb5_key subkey)173 make_fake_cfx_context(krb5_key subkey)
174 {
175     gss_union_ctx_id_t uctx;
176     krb5_gss_ctx_id_t kgctx;
177 
178     kgctx = ealloc(sizeof(*kgctx));
179     kgctx->established = 1;
180     kgctx->proto = 1;
181     if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
182         abort();
183     kgctx->mech_used = &mech_krb5;
184     kgctx->sealalg = -1;
185     kgctx->signalg = -1;
186 
187     kgctx->subkey = subkey;
188     kgctx->cksumtype = CKSUMTYPE_HMAC_SHA1_96_AES128;
189 
190     uctx = ealloc(sizeof(*uctx));
191     uctx->mech_type = &mech_krb5;
192     uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
193     return (gss_ctx_id_t)uctx;
194 }
195 
196 /* Fake up enough of a GSS context for gss_unwrap, using keys from test. */
197 static gss_ctx_id_t
make_fake_context(const struct test * test)198 make_fake_context(const struct test *test)
199 {
200     gss_union_ctx_id_t uctx;
201     krb5_gss_ctx_id_t kgctx;
202     krb5_keyblock kb;
203 
204     kgctx = ealloc(sizeof(*kgctx));
205     kgctx->established = 1;
206     if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
207         abort();
208     kgctx->mech_used = &mech_krb5;
209     kgctx->sealalg = test->sealalg;
210     kgctx->signalg = test->signalg;
211     kgctx->cksum_size = test->cksum_size;
212 
213     kb.enctype = test->enctype;
214     kb.length = test->keylen;
215     kb.contents = (unsigned char *)test->keydata;
216     if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
217         abort();
218 
219     kb.enctype = test->encseq_enctype;
220     if (krb5_k_create_key(NULL, &kb, &kgctx->seq) != 0)
221         abort();
222 
223     if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
224         abort();
225 
226     uctx = ealloc(sizeof(*uctx));
227     uctx->mech_type = &mech_krb5;
228     uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
229     return (gss_ctx_id_t)uctx;
230 }
231 
232 /* Free a context created by make_fake_context. */
233 static void
free_fake_context(gss_ctx_id_t ctx)234 free_fake_context(gss_ctx_id_t ctx)
235 {
236     gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx;
237     krb5_gss_ctx_id_t kgctx = (krb5_gss_ctx_id_t)uctx->internal_ctx_id;
238 
239     free(kgctx->seqstate);
240     krb5_k_free_key(NULL, kgctx->subkey);
241     krb5_k_free_key(NULL, kgctx->seq);
242     krb5_k_free_key(NULL, kgctx->enc);
243     free(kgctx);
244     free(uctx);
245 }
246 
247 /* Prefix a token (starting at the two-byte ID) with an ASN.1 header and return
248  * it in an allocated block to facilitate checking by valgrind or similar. */
249 static void
make_token(unsigned char * token,size_t len,gss_buffer_t out)250 make_token(unsigned char *token, size_t len, gss_buffer_t out)
251 {
252     char *wrapped;
253 
254     assert(mech_krb5.length == 9);
255     assert(len + 11 < 128);
256     wrapped = ealloc(len + 13);
257     wrapped[0] = 0x60;
258     wrapped[1] = len + 11;
259     wrapped[2] = 0x06;
260     wrapped[3] = 9;
261     memcpy(wrapped + 4, mech_krb5.elements, 9);
262     memcpy(wrapped + 13, token, len);
263     out->length = len + 13;
264     out->value = wrapped;
265 }
266 
267 /* Create a 16-byte header for a CFX confidential wrap token to be processed by
268  * the fake CFX context. */
269 static void
write_cfx_header(uint16_t ec,uint8_t * out)270 write_cfx_header(uint16_t ec, uint8_t *out)
271 {
272     memset(out, 0, 16);
273     store_16_be(KG2_TOK_WRAP_MSG, out);
274     out[2] = FLAG_WRAP_CONFIDENTIAL;
275     out[3] = 0xFF;
276     store_16_be(ec, out + 4);
277 }
278 
279 /* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
280  * regular and IOV unwrap. */
281 static void
test_bogus_1964_token(gss_ctx_id_t ctx)282 test_bogus_1964_token(gss_ctx_id_t ctx)
283 {
284     OM_uint32 minor, major;
285     unsigned char tokbuf[128];
286     gss_buffer_desc in, out;
287     gss_iov_buffer_desc iov;
288 
289     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
290     store_16_le(SGN_ALG_HMAC_MD5, tokbuf + 2);
291     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
292     store_16_le(0xFFFF, tokbuf + 6);
293     memset(tokbuf + 8, 0, 16);
294     make_token(tokbuf, 24, &in);
295 
296     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
297     if (major != GSS_S_DEFECTIVE_TOKEN)
298         abort();
299     (void)gss_release_buffer(&minor, &out);
300 
301     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
302     iov.buffer = in;
303     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
304     if (major != GSS_S_DEFECTIVE_TOKEN)
305         abort();
306 
307     free(in.value);
308 }
309 
310 static void
test_cfx_altered_ec(gss_ctx_id_t ctx,krb5_key subkey)311 test_cfx_altered_ec(gss_ctx_id_t ctx, krb5_key subkey)
312 {
313     OM_uint32 major, minor;
314     uint8_t tokbuf[128], plainbuf[24];
315     krb5_data plain;
316     krb5_enc_data cipher;
317     gss_buffer_desc in, out;
318     gss_iov_buffer_desc iov[2];
319 
320     /* Construct a header with a plaintext EC value of 3. */
321     write_cfx_header(3, tokbuf);
322 
323     /* Encrypt a plaintext and a copy of the header with the EC value 0. */
324     memcpy(plainbuf, "truncate", 8);
325     memcpy(plainbuf + 8, tokbuf, 16);
326     store_16_be(0, plainbuf + 12);
327     plain = make_data(plainbuf, 24);
328     cipher.ciphertext.data = (char *)tokbuf + 16;
329     cipher.ciphertext.length = sizeof(tokbuf) - 16;
330     cipher.enctype = subkey->keyblock.enctype;
331     if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
332                        &plain, &cipher) != 0)
333         abort();
334 
335     /* Verify that the token is rejected by gss_unwrap(). */
336     in.value = tokbuf;
337     in.length = 16 + cipher.ciphertext.length;
338     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
339     if (major != GSS_S_DEFECTIVE_TOKEN)
340         abort();
341     (void)gss_release_buffer(&minor, &out);
342 
343     /* Verify that the token is rejected by gss_unwrap_iov(). */
344     iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
345     iov[0].buffer = in;
346     iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
347     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
348     if (major != GSS_S_DEFECTIVE_TOKEN)
349         abort();
350 }
351 
352 static void
test_cfx_short_plaintext(gss_ctx_id_t ctx,krb5_key subkey)353 test_cfx_short_plaintext(gss_ctx_id_t ctx, krb5_key subkey)
354 {
355     OM_uint32 major, minor;
356     uint8_t tokbuf[128], zerobyte = 0;
357     krb5_data plain;
358     krb5_enc_data cipher;
359     gss_buffer_desc in, out;
360 
361     write_cfx_header(0, tokbuf);
362 
363     /* Encrypt a single byte, with no copy of the header. */
364     plain = make_data(&zerobyte, 1);
365     cipher.ciphertext.data = (char *)tokbuf + 16;
366     cipher.ciphertext.length = sizeof(tokbuf) - 16;
367     cipher.enctype = subkey->keyblock.enctype;
368     if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
369                        &plain, &cipher) != 0)
370         abort();
371 
372     /* Verify that the token is rejected by gss_unwrap(). */
373     in.value = tokbuf;
374     in.length = 16 + cipher.ciphertext.length;
375     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
376     if (major != GSS_S_DEFECTIVE_TOKEN)
377         abort();
378     (void)gss_release_buffer(&minor, &out);
379 }
380 
381 static void
test_cfx_large_ec(gss_ctx_id_t ctx,krb5_key subkey)382 test_cfx_large_ec(gss_ctx_id_t ctx, krb5_key subkey)
383 {
384     OM_uint32 major, minor;
385     uint8_t tokbuf[128] = { 0 }, plainbuf[20];
386     krb5_data plain;
387     krb5_enc_data cipher;
388     gss_buffer_desc in, out;
389 
390     /* Construct a header with an EC value of 5. */
391     write_cfx_header(5, tokbuf);
392 
393     /* Encrypt a 4-byte plaintext plus the header. */
394     memcpy(plainbuf, "abcd", 4);
395     memcpy(plainbuf + 4, tokbuf, 16);
396     plain = make_data(plainbuf, 20);
397     cipher.ciphertext.data = (char *)tokbuf + 16;
398     cipher.ciphertext.length = sizeof(tokbuf) - 16;
399     cipher.enctype = subkey->keyblock.enctype;
400     if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
401                        &plain, &cipher) != 0)
402         abort();
403 
404     /* Verify that the token is rejected by gss_unwrap(). */
405     in.value = tokbuf;
406     in.length = 16 + cipher.ciphertext.length;
407     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
408     if (major != GSS_S_DEFECTIVE_TOKEN)
409         abort();
410     (void)gss_release_buffer(&minor, &out);
411 }
412 
413 static void
test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)414 test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)
415 {
416     OM_uint32 minor, major;
417     uint8_t databuf[10] = { 0 };
418     gss_iov_buffer_desc iov[2];
419 
420     /*
421      * In this IOV array, the header contains a DER tag with a dangling eight
422      * bytes of length field.  The data IOV indicates a total token length
423      * sufficient to contain the length bytes.
424      */
425     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
426     iov[0].buffer.value = ealloc(2);
427     iov[0].buffer.length = 2;
428     memcpy(iov[0].buffer.value, "\x60\x88", 2);
429     iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
430     iov[1].buffer.value = databuf;
431     iov[1].buffer.length = 10;
432     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
433     if (major != GSS_S_DEFECTIVE_TOKEN)
434         abort();
435     free(iov[0].buffer.value);
436 }
437 
438 /* Verify that token is a valid MIC token for ctx and message, and that
439  * changing any of the input bytes yields one of the expected errors. */
440 static void
mictest(gss_ctx_id_t ctx,gss_buffer_t message,gss_buffer_t token)441 mictest(gss_ctx_id_t ctx, gss_buffer_t message, gss_buffer_t token)
442 {
443     OM_uint32 major, minor;
444     size_t i;
445     uint8_t *p;
446 
447     major = gss_verify_mic(&minor, ctx, message, token, NULL);
448     check_gsserr("gss_verify_mic", major, minor);
449 
450     p = token->value;
451     for (i = 0; i < token->length; i++) {
452         /* Skip sequence number bytes for RC4. */
453         if (load_16_le(p + 15) == SGN_ALG_HMAC_MD5 && i >= 21 && i <= 24)
454             continue;
455         p[i]++;
456         major = gss_verify_mic(&minor, ctx, message, token, NULL);
457         if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG)
458             abort();
459         p[i]--;
460     }
461     p = message->value;
462     for (i = 0; i < message->length; i++) {
463         p[i]++;
464         major = gss_verify_mic(&minor, ctx, message, token, NULL);
465         if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG)
466             abort();
467         p[i]--;
468     }
469 }
470 
471 static void
test_cfx_verify_mic(gss_ctx_id_t ctx)472 test_cfx_verify_mic(gss_ctx_id_t ctx)
473 {
474     gss_buffer_desc message, token;
475     uint8_t msg[] = "message";
476     uint8_t mic[] = "\x04\x04\x00\xFF\xFF\xFF\xFF\xFF"
477         "\x00\x00\x00\x00\x00\x00\x00\x00\x97\xE9\x63\x3F\x9D\x82\x2B\x74"
478         "\x67\x94\x8A\xD0";
479 
480     message.value = msg;
481     message.length = sizeof(msg) - 1;
482     token.value = mic;
483     token.length = sizeof(mic) - 1;
484     mictest(ctx, &message, &token);
485 }
486 
487 static void
test_verify_mic(gss_ctx_id_t ctx,const struct test * test)488 test_verify_mic(gss_ctx_id_t ctx, const struct test *test)
489 {
490     gss_buffer_desc message, token;
491     uint8_t msg[] = "message", buf[128];
492 
493     assert(test->miclen <= sizeof(buf));
494     memcpy(buf, test->mic, test->miclen);
495 
496     message.value = msg;
497     message.length = sizeof(msg) - 1;
498     token.value = buf;
499     token.length = test->miclen;
500     mictest(ctx, &message, &token);
501 }
502 
503 /* Verify that token is a valid wrap token for ctx unwrapping to message, and
504  * that changing any of the token bytes yields one of the expected errors. */
505 static void
unwraptest(gss_ctx_id_t ctx,gss_buffer_t message,gss_buffer_t token)506 unwraptest(gss_ctx_id_t ctx, gss_buffer_t message, gss_buffer_t token)
507 {
508     OM_uint32 major, minor;
509     gss_buffer_desc unwrapped;
510     size_t i;
511     uint8_t *p;
512 
513     major = gss_unwrap(&minor, ctx, token, &unwrapped, NULL, NULL);
514     check_gsserr("gss_unwrap", major, minor);
515     if (unwrapped.length != message->length ||
516         memcmp(unwrapped.value, message->value, unwrapped.length) != 0)
517         abort();
518     gss_release_buffer(&minor, &unwrapped);
519 
520     p = token->value;
521     for (i = 0; i < token->length; i++) {
522         /* Skip sequence number bytes for RC4. */
523         if (load_16_le(p + 15) == SGN_ALG_HMAC_MD5 && i >= 21 && i <= 24)
524             continue;
525         p[i]++;
526         major = gss_unwrap(&minor, ctx, token, &unwrapped, NULL, NULL);
527         if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG)
528             abort();
529         p[i]--;
530     }
531 }
532 
533 static void
test_cfx_unwrap(gss_ctx_id_t ctx)534 test_cfx_unwrap(gss_ctx_id_t ctx)
535 {
536     gss_buffer_desc message, token;
537     uint8_t msg[] = "message";
538     uint8_t token1[] = "\x05\x04\x00\xFF\x00\x0C\x00\x00"
539         "\x00\x00\x00\x00\x00\x00\x00\x00\x6D\x65\x73\x73\x61\x67\x65\xDF"
540         "\x57\xB9\x5E\xA2\xB1\x73\x31\xDB\xCE\x61\x62";
541     uint8_t token2[] = "\x05\x04\x02\xFF\x00\x00\x00\x00"
542         "\x00\x00\x00\x00\x00\x00\x00\x00\x72\xBB\xD7\xCF\xDE\xB0\xF9\x20"
543         "\xE2\x9A\x98\xA7\xA4\xE7\xC9\x9B\x30\xD3\xFE\x61\x51\x2E\x1B\x56"
544         "\x88\xB7\x8A\xF5\xA9\xBF\x8F\x82\xB1\xEB\xCC\x88\xE6\x33\x13\xBF"
545         "\x52\x4B\xC0\x3B\x24\x3F\x3E\xF5\xF1\xE0\x64";
546 
547     message.value = msg;
548     message.length = sizeof(msg) - 1;
549     token.value = token1;
550     token.length = sizeof(token1) - 1;
551     unwraptest(ctx, &message, &token);
552     token.value = token2;
553     token.length = sizeof(token2) - 1;
554     unwraptest(ctx, &message, &token);
555 }
556 
557 static void
test_unwrap(gss_ctx_id_t ctx,const struct test * test)558 test_unwrap(gss_ctx_id_t ctx, const struct test *test)
559 {
560     gss_buffer_desc message, token;
561     uint8_t msg[] = "message", buf[128];
562 
563     assert(test->wrap1len <= sizeof(buf) && test->wrap2len <= sizeof(buf));
564     token.value = buf;
565 
566     message.value = msg;
567     message.length = sizeof(msg) - 1;
568     memcpy(buf, test->wrap1, test->wrap1len);
569     token.length = test->wrap1len;
570     unwraptest(ctx, &message, &token);
571     memcpy(buf, test->wrap2, test->wrap2len);
572     token.length = test->wrap2len;
573     unwraptest(ctx, &message, &token);
574 }
575 
576 /* Process wrap and MIC tokens with incomplete headers. */
577 static void
test_short_header(gss_ctx_id_t ctx)578 test_short_header(gss_ctx_id_t ctx)
579 {
580     OM_uint32 minor, major;
581     unsigned char tokbuf[128];
582     gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
583 
584     /* Seal token, 2-24 bytes */
585     store_16_be(KG_TOK_SEAL_MSG, tokbuf);
586     make_token(tokbuf, 2, &in);
587     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
588     if (major != GSS_S_DEFECTIVE_TOKEN)
589         abort();
590     free(in.value);
591     (void)gss_release_buffer(&minor, &out);
592 
593     /* Sign token, 2-24 bytes */
594     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
595     make_token(tokbuf, 2, &in);
596     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
597     if (major != GSS_S_DEFECTIVE_TOKEN)
598         abort();
599     free(in.value);
600     (void)gss_release_buffer(&minor, &out);
601 
602     /* MIC token, 2-24 bytes */
603     store_16_be(KG_TOK_MIC_MSG, tokbuf);
604     make_token(tokbuf, 2, &in);
605     major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
606     if (major != GSS_S_DEFECTIVE_TOKEN)
607         abort();
608     free(in.value);
609 }
610 
611 /* Process wrap and MIC tokens with incomplete headers. */
612 static void
test_short_header_iov(gss_ctx_id_t ctx,const struct test * test)613 test_short_header_iov(gss_ctx_id_t ctx, const struct test *test)
614 {
615     OM_uint32 minor, major;
616     unsigned char tokbuf[128];
617     gss_iov_buffer_desc iov;
618 
619     /* IOV seal token, 16-23 bytes */
620     store_16_be(KG_TOK_SEAL_MSG, tokbuf);
621     store_16_le(test->signalg, tokbuf + 2);
622     store_16_le(test->sealalg, tokbuf + 4);
623     store_16_be(0xFFFF, tokbuf + 6);
624     memset(tokbuf + 8, 0, 8);
625     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
626     make_token(tokbuf, 16, &iov.buffer);
627     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
628     if (major != GSS_S_DEFECTIVE_TOKEN)
629         abort();
630     free(iov.buffer.value);
631 
632     /* IOV sign token, 16-23 bytes */
633     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
634     store_16_le(test->signalg, tokbuf + 2);
635     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
636     store_16_le(0xFFFF, tokbuf + 6);
637     memset(tokbuf + 8, 0, 8);
638     iov.type = GSS_IOV_BUFFER_TYPE_HEADER;
639     make_token(tokbuf, 16, &iov.buffer);
640     major = gss_unwrap_iov(&minor, ctx, NULL, NULL, &iov, 1);
641     if (major != GSS_S_DEFECTIVE_TOKEN)
642         abort();
643     free(iov.buffer.value);
644 
645     /* IOV MIC token, 16-23 bytes */
646     store_16_be(KG_TOK_MIC_MSG, tokbuf);
647     store_16_be(test->signalg, tokbuf + 2);
648     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
649     store_16_le(0xFFFF, tokbuf + 6);
650     memset(tokbuf + 8, 0, 8);
651     iov.type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
652     make_token(tokbuf, 16, &iov.buffer);
653     major = gss_verify_mic_iov(&minor, ctx, NULL, &iov, 1);
654     if (major != GSS_S_DEFECTIVE_TOKEN)
655         abort();
656     free(iov.buffer.value);
657 }
658 
659 /* Process wrap and MIC tokens with incomplete checksums. */
660 static void
test_short_checksum(gss_ctx_id_t ctx,const struct test * test)661 test_short_checksum(gss_ctx_id_t ctx, const struct test *test)
662 {
663     OM_uint32 minor, major;
664     unsigned char tokbuf[128];
665     gss_buffer_desc in, out, empty = GSS_C_EMPTY_BUFFER;
666 
667     /* Can only do this with the DES3 checksum, as we can't easily get past
668      * retrieving the sequence number when the checksum is only eight bytes. */
669     if (test->cksum_size <= 8)
670         return;
671     /* Seal token, fewer than 16 + cksum_size bytes.  Use the token from the
672      * test data to get a valid sequence number. */
673     make_token((unsigned char *)test->token + 13, 24, &in);
674     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
675     if (major != GSS_S_DEFECTIVE_TOKEN)
676         abort();
677     free(in.value);
678     (void)gss_release_buffer(&minor, &out);
679 
680     /* Sign token, fewer than 16 + cksum_size bytes. */
681     memcpy(tokbuf, test->token + 13, 24);
682     store_16_be(KG_TOK_SIGN_MSG, tokbuf);
683     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
684     make_token(tokbuf, 24, &in);
685     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
686     if (major != GSS_S_DEFECTIVE_TOKEN)
687         abort();
688     free(in.value);
689     (void)gss_release_buffer(&minor, &out);
690 
691     /* MIC token, fewer than 16 + cksum_size bytes. */
692     memcpy(tokbuf, test->token + 13, 24);
693     store_16_be(KG_TOK_MIC_MSG, tokbuf);
694     store_16_le(SEAL_ALG_NONE, tokbuf + 4);
695     make_token(tokbuf, 24, &in);
696     major = gss_verify_mic(&minor, ctx, &empty, &in, NULL);
697     if (major != GSS_S_DEFECTIVE_TOKEN)
698         abort();
699     free(in.value);
700 }
701 
702 /* Unwrap a token with a bogus padding byte in the decrypted ciphertext. */
703 static void
test_bad_pad(gss_ctx_id_t ctx,const struct test * test)704 test_bad_pad(gss_ctx_id_t ctx, const struct test *test)
705 {
706     OM_uint32 minor, major;
707     gss_buffer_desc in, out;
708 
709     in.length = test->toklen;
710     in.value = (char *)test->token;
711     major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
712     if (major != GSS_S_BAD_SIG)
713         abort();
714     (void)gss_release_buffer(&minor, &out);
715 }
716 
717 static void
try_accept(void * value,size_t len)718 try_accept(void *value, size_t len)
719 {
720     OM_uint32 minor;
721     gss_buffer_desc in, out;
722     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
723 
724     /* Copy the provided value to make input overruns more obvious. */
725     in.value = ealloc(len);
726     memcpy(in.value, value, len);
727     in.length = len;
728     (void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
729                                  GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
730                                  &out, NULL, NULL, NULL);
731     gss_release_buffer(&minor, &out);
732     gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
733     free(in.value);
734 }
735 
736 /* Accept contexts using superficially valid but truncated encapsulations. */
737 static void
test_short_encapsulation(void)738 test_short_encapsulation(void)
739 {
740     /* Include just the initial application tag, to see if we overrun reading
741      * the sequence length. */
742     try_accept("\x60", 1);
743 
744     /* Indicate four additional sequence length bytes, to see if we overrun
745      * reading them (or skipping them and reading the next byte). */
746     try_accept("\x60\x84", 2);
747 
748     /* Include an object identifier tag but no length, to see if we overrun
749      * reading the length. */
750     try_accept("\x60\x40\x06", 3);
751 
752     /* Include an object identifier tag with a length matching the krb5 mech,
753      * but no OID bytes, to see if we overrun comparing against mechs. */
754     try_accept("\x60\x40\x06\x09", 4);
755 }
756 
757 int
main(int argc,char ** argv)758 main(int argc, char **argv)
759 {
760     krb5_keyblock kb;
761     krb5_key cfx_subkey;
762     gss_ctx_id_t ctx;
763     size_t i;
764 
765     kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
766     kb.length = 16;
767     kb.contents = (unsigned char *)"1234567887654321";
768     if (krb5_k_create_key(NULL, &kb, &cfx_subkey) != 0)
769         abort();
770 
771     ctx = make_fake_cfx_context(cfx_subkey);
772     test_bogus_1964_token(ctx);
773     test_cfx_altered_ec(ctx, cfx_subkey);
774     test_cfx_short_plaintext(ctx, cfx_subkey);
775     test_cfx_large_ec(ctx, cfx_subkey);
776     test_iov_large_asn1_wrapper(ctx);
777     test_cfx_verify_mic(ctx);
778     test_cfx_unwrap(ctx);
779     free_fake_context(ctx);
780 
781     for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
782         ctx = make_fake_context(&tests[i]);
783         test_short_header(ctx);
784         test_short_header_iov(ctx, &tests[i]);
785         test_short_checksum(ctx, &tests[i]);
786         test_bad_pad(ctx, &tests[i]);
787         test_verify_mic(ctx, &tests[i]);
788         test_unwrap(ctx, &tests[i]);
789         free_fake_context(ctx);
790     }
791 
792     test_short_encapsulation();
793 
794     return 0;
795 }
796