Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/tests/gssapi/t_invalid.c
34889 views
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
797