Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/krb5/cfx.c
34923 views
1
/*
2
* Copyright (c) 2003, PADL Software Pty Ltd.
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
*
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
*
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* 3. Neither the name of PADL Software nor the names of its contributors
17
* may be used to endorse or promote products derived from this software
18
* without specific prior written permission.
19
*
20
* THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*/
32
33
#include "gsskrb5_locl.h"
34
35
/*
36
* Implementation of RFC 4121
37
*/
38
39
#define CFXSentByAcceptor (1 << 0)
40
#define CFXSealed (1 << 1)
41
#define CFXAcceptorSubkey (1 << 2)
42
43
krb5_error_code
44
_gsskrb5cfx_wrap_length_cfx(krb5_context context,
45
krb5_crypto crypto,
46
int conf_req_flag,
47
int dce_style,
48
size_t input_length,
49
size_t *output_length,
50
size_t *cksumsize,
51
uint16_t *padlength)
52
{
53
krb5_error_code ret;
54
krb5_cksumtype type;
55
56
/* 16-byte header is always first */
57
*output_length = sizeof(gss_cfx_wrap_token_desc);
58
*padlength = 0;
59
60
ret = krb5_crypto_get_checksum_type(context, crypto, &type);
61
if (ret)
62
return ret;
63
64
ret = krb5_checksumsize(context, type, cksumsize);
65
if (ret)
66
return ret;
67
68
if (conf_req_flag) {
69
size_t padsize;
70
71
/* Header is concatenated with data before encryption */
72
input_length += sizeof(gss_cfx_wrap_token_desc);
73
74
if (dce_style) {
75
ret = krb5_crypto_getblocksize(context, crypto, &padsize);
76
} else {
77
ret = krb5_crypto_getpadsize(context, crypto, &padsize);
78
}
79
if (ret) {
80
return ret;
81
}
82
if (padsize > 1) {
83
/* XXX check this */
84
*padlength = padsize - (input_length % padsize);
85
86
/* We add the pad ourselves (noted here for completeness only) */
87
input_length += *padlength;
88
}
89
90
*output_length += krb5_get_wrapped_length(context,
91
crypto, input_length);
92
} else {
93
/* Checksum is concatenated with data */
94
*output_length += input_length + *cksumsize;
95
}
96
97
assert(*output_length > input_length);
98
99
return 0;
100
}
101
102
OM_uint32
103
_gssapi_wrap_size_cfx(OM_uint32 *minor_status,
104
const gsskrb5_ctx ctx,
105
krb5_context context,
106
int conf_req_flag,
107
gss_qop_t qop_req,
108
OM_uint32 req_output_size,
109
OM_uint32 *max_input_size)
110
{
111
krb5_error_code ret;
112
113
*max_input_size = 0;
114
115
/* 16-byte header is always first */
116
if (req_output_size < 16)
117
return 0;
118
req_output_size -= 16;
119
120
if (conf_req_flag) {
121
size_t wrapped_size, sz;
122
123
wrapped_size = req_output_size + 1;
124
do {
125
wrapped_size--;
126
sz = krb5_get_wrapped_length(context,
127
ctx->crypto, wrapped_size);
128
} while (wrapped_size && sz > req_output_size);
129
if (wrapped_size == 0)
130
return 0;
131
132
/* inner header */
133
if (wrapped_size < 16)
134
return 0;
135
136
wrapped_size -= 16;
137
138
*max_input_size = wrapped_size;
139
} else {
140
krb5_cksumtype type;
141
size_t cksumsize;
142
143
ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);
144
if (ret)
145
return ret;
146
147
ret = krb5_checksumsize(context, type, &cksumsize);
148
if (ret)
149
return ret;
150
151
if (req_output_size < cksumsize)
152
return 0;
153
154
/* Checksum is concatenated with data */
155
*max_input_size = req_output_size - cksumsize;
156
}
157
158
return 0;
159
}
160
161
/*
162
* Rotate "rrc" bytes to the front or back
163
*/
164
165
static krb5_error_code
166
rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
167
{
168
u_char *tmp, buf[256];
169
size_t left;
170
171
if (len == 0)
172
return 0;
173
174
rrc %= len;
175
176
if (rrc == 0)
177
return 0;
178
179
left = len - rrc;
180
181
if (rrc <= sizeof(buf)) {
182
tmp = buf;
183
} else {
184
tmp = malloc(rrc);
185
if (tmp == NULL)
186
return ENOMEM;
187
}
188
189
if (unrotate) {
190
memcpy(tmp, data, rrc);
191
memmove(data, (u_char *)data + rrc, left);
192
memcpy((u_char *)data + left, tmp, rrc);
193
} else {
194
memcpy(tmp, (u_char *)data + left, rrc);
195
memmove((u_char *)data + rrc, data, left);
196
memcpy(data, tmp, rrc);
197
}
198
199
if (rrc > sizeof(buf))
200
free(tmp);
201
202
return 0;
203
}
204
205
gss_iov_buffer_desc *
206
_gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
207
{
208
int i;
209
210
for (i = 0; i < iov_count; i++)
211
if (type == GSS_IOV_BUFFER_TYPE(iov[i].type))
212
return &iov[i];
213
return NULL;
214
}
215
216
OM_uint32
217
_gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size)
218
{
219
if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
220
if (buffer->buffer.length == size)
221
return GSS_S_COMPLETE;
222
free(buffer->buffer.value);
223
}
224
225
buffer->buffer.value = malloc(size);
226
buffer->buffer.length = size;
227
if (buffer->buffer.value == NULL) {
228
*minor_status = ENOMEM;
229
return GSS_S_FAILURE;
230
}
231
buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
232
233
return GSS_S_COMPLETE;
234
}
235
236
237
OM_uint32
238
_gk_verify_buffers(OM_uint32 *minor_status,
239
const gsskrb5_ctx ctx,
240
const gss_iov_buffer_desc *header,
241
const gss_iov_buffer_desc *padding,
242
const gss_iov_buffer_desc *trailer)
243
{
244
if (header == NULL) {
245
*minor_status = EINVAL;
246
return GSS_S_FAILURE;
247
}
248
249
if (IS_DCE_STYLE(ctx)) {
250
/*
251
* In DCE style mode we reject having a padding or trailer buffer
252
*/
253
if (padding) {
254
*minor_status = EINVAL;
255
return GSS_S_FAILURE;
256
}
257
if (trailer) {
258
*minor_status = EINVAL;
259
return GSS_S_FAILURE;
260
}
261
} else {
262
/*
263
* In non-DCE style mode we require having a padding buffer
264
*/
265
if (padding == NULL) {
266
*minor_status = EINVAL;
267
return GSS_S_FAILURE;
268
}
269
}
270
271
*minor_status = 0;
272
return GSS_S_COMPLETE;
273
}
274
275
#if 0
276
OM_uint32
277
_gssapi_wrap_cfx_iov(OM_uint32 *minor_status,
278
gsskrb5_ctx ctx,
279
krb5_context context,
280
int conf_req_flag,
281
int *conf_state,
282
gss_iov_buffer_desc *iov,
283
int iov_count)
284
{
285
OM_uint32 major_status, junk;
286
gss_iov_buffer_desc *header, *trailer, *padding;
287
size_t gsshsize, k5hsize;
288
size_t gsstsize, k5tsize;
289
size_t rrc = 0, ec = 0;
290
int i;
291
gss_cfx_wrap_token token;
292
krb5_error_code ret;
293
int32_t seq_number;
294
unsigned usage;
295
krb5_crypto_iov *data = NULL;
296
297
header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
298
if (header == NULL) {
299
*minor_status = EINVAL;
300
return GSS_S_FAILURE;
301
}
302
303
padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
304
if (padding != NULL) {
305
padding->buffer.length = 0;
306
}
307
308
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
309
310
major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
311
if (major_status != GSS_S_COMPLETE) {
312
return major_status;
313
}
314
315
if (conf_req_flag) {
316
size_t k5psize = 0;
317
size_t k5pbase = 0;
318
size_t k5bsize = 0;
319
size_t size = 0;
320
321
for (i = 0; i < iov_count; i++) {
322
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
323
case GSS_IOV_BUFFER_TYPE_DATA:
324
size += iov[i].buffer.length;
325
break;
326
default:
327
break;
328
}
329
}
330
331
size += sizeof(gss_cfx_wrap_token_desc);
332
333
*minor_status = krb5_crypto_length(context, ctx->crypto,
334
KRB5_CRYPTO_TYPE_HEADER,
335
&k5hsize);
336
if (*minor_status)
337
return GSS_S_FAILURE;
338
339
*minor_status = krb5_crypto_length(context, ctx->crypto,
340
KRB5_CRYPTO_TYPE_TRAILER,
341
&k5tsize);
342
if (*minor_status)
343
return GSS_S_FAILURE;
344
345
*minor_status = krb5_crypto_length(context, ctx->crypto,
346
KRB5_CRYPTO_TYPE_PADDING,
347
&k5pbase);
348
if (*minor_status)
349
return GSS_S_FAILURE;
350
351
if (k5pbase > 1) {
352
k5psize = k5pbase - (size % k5pbase);
353
} else {
354
k5psize = 0;
355
}
356
357
if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
358
*minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
359
&k5bsize);
360
if (*minor_status)
361
return GSS_S_FAILURE;
362
ec = k5bsize;
363
} else {
364
ec = k5psize;
365
}
366
367
gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
368
gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
369
} else {
370
if (IS_DCE_STYLE(ctx)) {
371
*minor_status = EINVAL;
372
return GSS_S_FAILURE;
373
}
374
375
k5hsize = 0;
376
*minor_status = krb5_crypto_length(context, ctx->crypto,
377
KRB5_CRYPTO_TYPE_CHECKSUM,
378
&k5tsize);
379
if (*minor_status)
380
return GSS_S_FAILURE;
381
382
gsshsize = sizeof(gss_cfx_wrap_token_desc);
383
gsstsize = k5tsize;
384
}
385
386
/*
387
*
388
*/
389
390
if (trailer == NULL) {
391
rrc = gsstsize;
392
if (IS_DCE_STYLE(ctx))
393
rrc -= ec;
394
gsshsize += gsstsize;
395
gsstsize = 0;
396
} else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
397
major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize);
398
if (major_status)
399
goto failure;
400
} else if (trailer->buffer.length < gsstsize) {
401
*minor_status = KRB5_BAD_MSIZE;
402
major_status = GSS_S_FAILURE;
403
goto failure;
404
} else
405
trailer->buffer.length = gsstsize;
406
407
/*
408
*
409
*/
410
411
if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
412
major_status = _gk_allocate_buffer(minor_status, header, gsshsize);
413
if (major_status != GSS_S_COMPLETE)
414
goto failure;
415
} else if (header->buffer.length < gsshsize) {
416
*minor_status = KRB5_BAD_MSIZE;
417
major_status = GSS_S_FAILURE;
418
goto failure;
419
} else
420
header->buffer.length = gsshsize;
421
422
token = (gss_cfx_wrap_token)header->buffer.value;
423
424
token->TOK_ID[0] = 0x05;
425
token->TOK_ID[1] = 0x04;
426
token->Flags = 0;
427
token->Filler = 0xFF;
428
429
if ((ctx->more_flags & LOCAL) == 0)
430
token->Flags |= CFXSentByAcceptor;
431
432
if (ctx->more_flags & ACCEPTOR_SUBKEY)
433
token->Flags |= CFXAcceptorSubkey;
434
435
if (ctx->more_flags & LOCAL)
436
usage = KRB5_KU_USAGE_INITIATOR_SEAL;
437
else
438
usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
439
440
if (conf_req_flag) {
441
/*
442
* In Wrap tokens with confidentiality, the EC field is
443
* used to encode the size (in bytes) of the random filler.
444
*/
445
token->Flags |= CFXSealed;
446
token->EC[0] = (ec >> 8) & 0xFF;
447
token->EC[1] = (ec >> 0) & 0xFF;
448
449
} else {
450
/*
451
* In Wrap tokens without confidentiality, the EC field is
452
* used to encode the size (in bytes) of the trailing
453
* checksum.
454
*
455
* This is not used in the checksum calcuation itself,
456
* because the checksum length could potentially vary
457
* depending on the data length.
458
*/
459
token->EC[0] = 0;
460
token->EC[1] = 0;
461
}
462
463
/*
464
* In Wrap tokens that provide for confidentiality, the RRC
465
* field in the header contains the hex value 00 00 before
466
* encryption.
467
*
468
* In Wrap tokens that do not provide for confidentiality,
469
* both the EC and RRC fields in the appended checksum
470
* contain the hex value 00 00 for the purpose of calculating
471
* the checksum.
472
*/
473
token->RRC[0] = 0;
474
token->RRC[1] = 0;
475
476
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
477
krb5_auth_con_getlocalseqnumber(context,
478
ctx->auth_context,
479
&seq_number);
480
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
481
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
482
krb5_auth_con_setlocalseqnumber(context,
483
ctx->auth_context,
484
++seq_number);
485
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
486
487
data = calloc(iov_count + 3, sizeof(data[0]));
488
if (data == NULL) {
489
*minor_status = ENOMEM;
490
major_status = GSS_S_FAILURE;
491
goto failure;
492
}
493
494
if (conf_req_flag) {
495
/*
496
plain packet:
497
498
{"header" | encrypt(plaintext-data | ec-padding | E"header")}
499
500
Expanded, this is with with RRC = 0:
501
502
{"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }
503
504
In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)
505
506
{"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data }
507
*/
508
509
i = 0;
510
data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
511
data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
512
data[i].data.length = k5hsize;
513
514
for (i = 1; i < iov_count + 1; i++) {
515
switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
516
case GSS_IOV_BUFFER_TYPE_DATA:
517
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
518
break;
519
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
520
data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
521
break;
522
default:
523
data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
524
break;
525
}
526
data[i].data.length = iov[i - 1].buffer.length;
527
data[i].data.data = iov[i - 1].buffer.value;
528
}
529
530
/*
531
* Any necessary padding is added here to ensure that the
532
* encrypted token header is always at the end of the
533
* ciphertext.
534
*/
535
536
/* encrypted CFX header in trailer (or after the header if in
537
DCE mode). Copy in header into E"header"
538
*/
539
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
540
if (trailer)
541
data[i].data.data = trailer->buffer.value;
542
else
543
data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
544
545
data[i].data.length = ec + sizeof(*token);
546
memset(data[i].data.data, 0xFF, ec);
547
memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
548
i++;
549
550
/* Kerberos trailer comes after the gss trailer */
551
data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
552
data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
553
data[i].data.length = k5tsize;
554
i++;
555
556
ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
557
if (ret != 0) {
558
*minor_status = ret;
559
major_status = GSS_S_FAILURE;
560
goto failure;
561
}
562
563
if (rrc) {
564
token->RRC[0] = (rrc >> 8) & 0xFF;
565
token->RRC[1] = (rrc >> 0) & 0xFF;
566
}
567
568
} else {
569
/*
570
plain packet:
571
572
{data | "header" | gss-trailer (krb5 checksum)
573
574
don't do RRC != 0
575
576
*/
577
578
for (i = 0; i < iov_count; i++) {
579
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
580
case GSS_IOV_BUFFER_TYPE_DATA:
581
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
582
break;
583
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
584
data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
585
break;
586
default:
587
data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
588
break;
589
}
590
data[i].data.length = iov[i].buffer.length;
591
data[i].data.data = iov[i].buffer.value;
592
}
593
594
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
595
data[i].data.data = header->buffer.value;
596
data[i].data.length = sizeof(gss_cfx_wrap_token_desc);
597
i++;
598
599
data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
600
if (trailer) {
601
data[i].data.data = trailer->buffer.value;
602
} else {
603
data[i].data.data = (uint8_t *)header->buffer.value +
604
sizeof(gss_cfx_wrap_token_desc);
605
}
606
data[i].data.length = k5tsize;
607
i++;
608
609
ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
610
if (ret) {
611
*minor_status = ret;
612
major_status = GSS_S_FAILURE;
613
goto failure;
614
}
615
616
if (rrc) {
617
token->RRC[0] = (rrc >> 8) & 0xFF;
618
token->RRC[1] = (rrc >> 0) & 0xFF;
619
}
620
621
token->EC[0] = (k5tsize >> 8) & 0xFF;
622
token->EC[1] = (k5tsize >> 0) & 0xFF;
623
}
624
625
if (conf_state != NULL)
626
*conf_state = conf_req_flag;
627
628
free(data);
629
630
*minor_status = 0;
631
return GSS_S_COMPLETE;
632
633
failure:
634
if (data)
635
free(data);
636
637
gss_release_iov_buffer(&junk, iov, iov_count);
638
639
return major_status;
640
}
641
#endif
642
643
/* This is slowpath */
644
static OM_uint32
645
unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count)
646
{
647
uint8_t *p, *q;
648
size_t len = 0, skip;
649
int i;
650
651
for (i = 0; i < iov_count; i++)
652
if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
653
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
654
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
655
len += iov[i].buffer.length;
656
657
p = malloc(len);
658
if (p == NULL) {
659
*minor_status = ENOMEM;
660
return GSS_S_FAILURE;
661
}
662
q = p;
663
664
/* copy up */
665
666
for (i = 0; i < iov_count; i++) {
667
if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
668
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
669
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
670
{
671
memcpy(q, iov[i].buffer.value, iov[i].buffer.length);
672
q += iov[i].buffer.length;
673
}
674
}
675
assert((size_t)(q - p) == len);
676
677
/* unrotate first part */
678
q = p + rrc;
679
skip = rrc;
680
for (i = 0; i < iov_count; i++) {
681
if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
682
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
683
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
684
{
685
if (iov[i].buffer.length <= skip) {
686
skip -= iov[i].buffer.length;
687
} else {
688
memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip);
689
q += iov[i].buffer.length - skip;
690
skip = 0;
691
}
692
}
693
}
694
/* copy trailer */
695
q = p;
696
skip = rrc;
697
for (i = 0; i < iov_count; i++) {
698
if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
699
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
700
GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
701
{
702
memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip));
703
if (iov[i].buffer.length > skip)
704
break;
705
skip -= iov[i].buffer.length;
706
q += iov[i].buffer.length;
707
}
708
}
709
return GSS_S_COMPLETE;
710
}
711
712
#if 0
713
714
OM_uint32
715
_gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,
716
gsskrb5_ctx ctx,
717
krb5_context context,
718
int *conf_state,
719
gss_qop_t *qop_state,
720
gss_iov_buffer_desc *iov,
721
int iov_count)
722
{
723
OM_uint32 seq_number_lo, seq_number_hi, major_status, junk;
724
gss_iov_buffer_desc *header, *trailer, *padding;
725
gss_cfx_wrap_token token, ttoken;
726
u_char token_flags;
727
krb5_error_code ret;
728
unsigned usage;
729
uint16_t ec, rrc;
730
krb5_crypto_iov *data = NULL;
731
int i, j;
732
733
*minor_status = 0;
734
735
header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
736
if (header == NULL) {
737
*minor_status = EINVAL;
738
return GSS_S_FAILURE;
739
}
740
741
if (header->buffer.length < sizeof(*token)) /* we check exact below */
742
return GSS_S_DEFECTIVE_TOKEN;
743
744
padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
745
if (padding != NULL && padding->buffer.length != 0) {
746
*minor_status = EINVAL;
747
return GSS_S_FAILURE;
748
}
749
750
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
751
752
major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
753
if (major_status != GSS_S_COMPLETE) {
754
return major_status;
755
}
756
757
token = (gss_cfx_wrap_token)header->buffer.value;
758
759
if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
760
return GSS_S_DEFECTIVE_TOKEN;
761
762
/* Ignore unknown flags */
763
token_flags = token->Flags &
764
(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
765
766
if (token_flags & CFXSentByAcceptor) {
767
if ((ctx->more_flags & LOCAL) == 0)
768
return GSS_S_DEFECTIVE_TOKEN;
769
}
770
771
if (ctx->more_flags & ACCEPTOR_SUBKEY) {
772
if ((token_flags & CFXAcceptorSubkey) == 0)
773
return GSS_S_DEFECTIVE_TOKEN;
774
} else {
775
if (token_flags & CFXAcceptorSubkey)
776
return GSS_S_DEFECTIVE_TOKEN;
777
}
778
779
if (token->Filler != 0xFF)
780
return GSS_S_DEFECTIVE_TOKEN;
781
782
if (conf_state != NULL)
783
*conf_state = (token_flags & CFXSealed) ? 1 : 0;
784
785
ec = (token->EC[0] << 8) | token->EC[1];
786
rrc = (token->RRC[0] << 8) | token->RRC[1];
787
788
/*
789
* Check sequence number
790
*/
791
_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
792
_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
793
if (seq_number_hi) {
794
/* no support for 64-bit sequence numbers */
795
*minor_status = ERANGE;
796
return GSS_S_UNSEQ_TOKEN;
797
}
798
799
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
800
ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
801
if (ret != 0) {
802
*minor_status = 0;
803
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
804
return ret;
805
}
806
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
807
808
/*
809
* Decrypt and/or verify checksum
810
*/
811
812
if (ctx->more_flags & LOCAL) {
813
usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
814
} else {
815
usage = KRB5_KU_USAGE_INITIATOR_SEAL;
816
}
817
818
data = calloc(iov_count + 3, sizeof(data[0]));
819
if (data == NULL) {
820
*minor_status = ENOMEM;
821
major_status = GSS_S_FAILURE;
822
goto failure;
823
}
824
825
if (token_flags & CFXSealed) {
826
size_t k5tsize, k5hsize;
827
828
krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
829
krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize);
830
831
/* Rotate by RRC; bogus to do this in-place XXX */
832
/* Check RRC */
833
834
if (trailer == NULL) {
835
size_t gsstsize = k5tsize + sizeof(*token);
836
size_t gsshsize = k5hsize + sizeof(*token);
837
838
if (rrc != gsstsize) {
839
major_status = GSS_S_DEFECTIVE_TOKEN;
840
goto failure;
841
}
842
843
if (IS_DCE_STYLE(ctx))
844
gsstsize += ec;
845
846
gsshsize += gsstsize;
847
848
if (header->buffer.length != gsshsize) {
849
major_status = GSS_S_DEFECTIVE_TOKEN;
850
goto failure;
851
}
852
} else if (trailer->buffer.length != sizeof(*token) + k5tsize) {
853
major_status = GSS_S_DEFECTIVE_TOKEN;
854
goto failure;
855
} else if (header->buffer.length != sizeof(*token) + k5hsize) {
856
major_status = GSS_S_DEFECTIVE_TOKEN;
857
goto failure;
858
} else if (rrc != 0) {
859
/* go though slowpath */
860
major_status = unrotate_iov(minor_status, rrc, iov, iov_count);
861
if (major_status)
862
goto failure;
863
}
864
865
i = 0;
866
data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
867
data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
868
data[i].data.length = k5hsize;
869
i++;
870
871
for (j = 0; j < iov_count; i++, j++) {
872
switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
873
case GSS_IOV_BUFFER_TYPE_DATA:
874
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
875
break;
876
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
877
data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
878
break;
879
default:
880
data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
881
break;
882
}
883
data[i].data.length = iov[j].buffer.length;
884
data[i].data.data = iov[j].buffer.value;
885
}
886
887
/* encrypted CFX header in trailer (or after the header if in
888
DCE mode). Copy in header into E"header"
889
*/
890
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
891
if (trailer) {
892
data[i].data.data = trailer->buffer.value;
893
} else {
894
data[i].data.data = ((uint8_t *)header->buffer.value) +
895
header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
896
}
897
898
data[i].data.length = ec + sizeof(*token);
899
ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
900
i++;
901
902
/* Kerberos trailer comes after the gss trailer */
903
data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
904
data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
905
data[i].data.length = k5tsize;
906
i++;
907
908
ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
909
if (ret != 0) {
910
*minor_status = ret;
911
major_status = GSS_S_FAILURE;
912
goto failure;
913
}
914
915
ttoken->RRC[0] = token->RRC[0];
916
ttoken->RRC[1] = token->RRC[1];
917
918
/* Check the integrity of the header */
919
if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) {
920
major_status = GSS_S_BAD_MIC;
921
goto failure;
922
}
923
} else {
924
size_t gsstsize = ec;
925
size_t gsshsize = sizeof(*token);
926
927
if (trailer == NULL) {
928
/* Check RRC */
929
if (rrc != gsstsize) {
930
*minor_status = EINVAL;
931
major_status = GSS_S_FAILURE;
932
goto failure;
933
}
934
935
gsshsize += gsstsize;
936
gsstsize = 0;
937
} else if (trailer->buffer.length != gsstsize) {
938
major_status = GSS_S_DEFECTIVE_TOKEN;
939
goto failure;
940
} else if (rrc != 0) {
941
/* Check RRC */
942
*minor_status = EINVAL;
943
major_status = GSS_S_FAILURE;
944
goto failure;
945
}
946
947
if (header->buffer.length != gsshsize) {
948
major_status = GSS_S_DEFECTIVE_TOKEN;
949
goto failure;
950
}
951
952
for (i = 0; i < iov_count; i++) {
953
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
954
case GSS_IOV_BUFFER_TYPE_DATA:
955
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
956
break;
957
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
958
data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
959
break;
960
default:
961
data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
962
break;
963
}
964
data[i].data.length = iov[i].buffer.length;
965
data[i].data.data = iov[i].buffer.value;
966
}
967
968
data[i].flags = KRB5_CRYPTO_TYPE_DATA;
969
data[i].data.data = header->buffer.value;
970
data[i].data.length = sizeof(*token);
971
i++;
972
973
data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
974
if (trailer) {
975
data[i].data.data = trailer->buffer.value;
976
} else {
977
data[i].data.data = (uint8_t *)header->buffer.value +
978
sizeof(*token);
979
}
980
data[i].data.length = ec;
981
i++;
982
983
token = (gss_cfx_wrap_token)header->buffer.value;
984
token->EC[0] = 0;
985
token->EC[1] = 0;
986
token->RRC[0] = 0;
987
token->RRC[1] = 0;
988
989
ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
990
if (ret) {
991
*minor_status = ret;
992
major_status = GSS_S_FAILURE;
993
goto failure;
994
}
995
}
996
997
if (qop_state != NULL) {
998
*qop_state = GSS_C_QOP_DEFAULT;
999
}
1000
1001
free(data);
1002
1003
*minor_status = 0;
1004
return GSS_S_COMPLETE;
1005
1006
failure:
1007
if (data)
1008
free(data);
1009
1010
gss_release_iov_buffer(&junk, iov, iov_count);
1011
1012
return major_status;
1013
}
1014
#endif
1015
1016
OM_uint32
1017
_gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,
1018
gsskrb5_ctx ctx,
1019
krb5_context context,
1020
int conf_req_flag,
1021
gss_qop_t qop_req,
1022
int *conf_state,
1023
gss_iov_buffer_desc *iov,
1024
int iov_count)
1025
{
1026
OM_uint32 major_status;
1027
size_t size;
1028
int i;
1029
gss_iov_buffer_desc *header = NULL;
1030
gss_iov_buffer_desc *padding = NULL;
1031
gss_iov_buffer_desc *trailer = NULL;
1032
size_t gsshsize = 0;
1033
size_t gsstsize = 0;
1034
size_t k5hsize = 0;
1035
size_t k5tsize = 0;
1036
1037
GSSAPI_KRB5_INIT (&context);
1038
*minor_status = 0;
1039
1040
for (size = 0, i = 0; i < iov_count; i++) {
1041
switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1042
case GSS_IOV_BUFFER_TYPE_EMPTY:
1043
break;
1044
case GSS_IOV_BUFFER_TYPE_DATA:
1045
size += iov[i].buffer.length;
1046
break;
1047
case GSS_IOV_BUFFER_TYPE_HEADER:
1048
if (header != NULL) {
1049
*minor_status = 0;
1050
return GSS_S_FAILURE;
1051
}
1052
header = &iov[i];
1053
break;
1054
case GSS_IOV_BUFFER_TYPE_TRAILER:
1055
if (trailer != NULL) {
1056
*minor_status = 0;
1057
return GSS_S_FAILURE;
1058
}
1059
trailer = &iov[i];
1060
break;
1061
case GSS_IOV_BUFFER_TYPE_PADDING:
1062
if (padding != NULL) {
1063
*minor_status = 0;
1064
return GSS_S_FAILURE;
1065
}
1066
padding = &iov[i];
1067
break;
1068
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
1069
break;
1070
default:
1071
*minor_status = EINVAL;
1072
return GSS_S_FAILURE;
1073
}
1074
}
1075
1076
major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
1077
if (major_status != GSS_S_COMPLETE) {
1078
return major_status;
1079
}
1080
1081
if (conf_req_flag) {
1082
size_t k5psize = 0;
1083
size_t k5pbase = 0;
1084
size_t k5bsize = 0;
1085
size_t ec = 0;
1086
1087
size += sizeof(gss_cfx_wrap_token_desc);
1088
1089
*minor_status = krb5_crypto_length(context, ctx->crypto,
1090
KRB5_CRYPTO_TYPE_HEADER,
1091
&k5hsize);
1092
if (*minor_status)
1093
return GSS_S_FAILURE;
1094
1095
*minor_status = krb5_crypto_length(context, ctx->crypto,
1096
KRB5_CRYPTO_TYPE_TRAILER,
1097
&k5tsize);
1098
if (*minor_status)
1099
return GSS_S_FAILURE;
1100
1101
*minor_status = krb5_crypto_length(context, ctx->crypto,
1102
KRB5_CRYPTO_TYPE_PADDING,
1103
&k5pbase);
1104
if (*minor_status)
1105
return GSS_S_FAILURE;
1106
1107
if (k5pbase > 1) {
1108
k5psize = k5pbase - (size % k5pbase);
1109
} else {
1110
k5psize = 0;
1111
}
1112
1113
if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
1114
*minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
1115
&k5bsize);
1116
if (*minor_status)
1117
return GSS_S_FAILURE;
1118
1119
ec = k5bsize;
1120
} else {
1121
ec = k5psize;
1122
}
1123
1124
gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
1125
gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
1126
} else {
1127
*minor_status = krb5_crypto_length(context, ctx->crypto,
1128
KRB5_CRYPTO_TYPE_CHECKSUM,
1129
&k5tsize);
1130
if (*minor_status)
1131
return GSS_S_FAILURE;
1132
1133
gsshsize = sizeof(gss_cfx_wrap_token_desc);
1134
gsstsize = k5tsize;
1135
}
1136
1137
if (trailer != NULL) {
1138
trailer->buffer.length = gsstsize;
1139
} else {
1140
gsshsize += gsstsize;
1141
}
1142
1143
header->buffer.length = gsshsize;
1144
1145
if (padding) {
1146
/* padding is done via EC and is contained in the header or trailer */
1147
padding->buffer.length = 0;
1148
}
1149
1150
if (conf_state) {
1151
*conf_state = conf_req_flag;
1152
}
1153
1154
return GSS_S_COMPLETE;
1155
}
1156
1157
1158
1159
1160
OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
1161
const gsskrb5_ctx ctx,
1162
krb5_context context,
1163
int conf_req_flag,
1164
const gss_buffer_t input_message_buffer,
1165
int *conf_state,
1166
gss_buffer_t output_message_buffer)
1167
{
1168
gss_cfx_wrap_token token;
1169
krb5_error_code ret;
1170
unsigned usage;
1171
krb5_data cipher;
1172
size_t wrapped_len, cksumsize;
1173
uint16_t padlength, rrc = 0;
1174
int32_t seq_number;
1175
u_char *p;
1176
1177
ret = _gsskrb5cfx_wrap_length_cfx(context,
1178
ctx->crypto, conf_req_flag,
1179
IS_DCE_STYLE(ctx),
1180
input_message_buffer->length,
1181
&wrapped_len, &cksumsize, &padlength);
1182
if (ret != 0) {
1183
*minor_status = ret;
1184
return GSS_S_FAILURE;
1185
}
1186
1187
/* Always rotate encrypted token (if any) and checksum to header */
1188
rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
1189
1190
output_message_buffer->length = wrapped_len;
1191
output_message_buffer->value = malloc(output_message_buffer->length);
1192
if (output_message_buffer->value == NULL) {
1193
*minor_status = ENOMEM;
1194
return GSS_S_FAILURE;
1195
}
1196
1197
p = output_message_buffer->value;
1198
token = (gss_cfx_wrap_token)p;
1199
token->TOK_ID[0] = 0x05;
1200
token->TOK_ID[1] = 0x04;
1201
token->Flags = 0;
1202
token->Filler = 0xFF;
1203
if ((ctx->more_flags & LOCAL) == 0)
1204
token->Flags |= CFXSentByAcceptor;
1205
if (ctx->more_flags & ACCEPTOR_SUBKEY)
1206
token->Flags |= CFXAcceptorSubkey;
1207
if (conf_req_flag) {
1208
/*
1209
* In Wrap tokens with confidentiality, the EC field is
1210
* used to encode the size (in bytes) of the random filler.
1211
*/
1212
token->Flags |= CFXSealed;
1213
token->EC[0] = (padlength >> 8) & 0xFF;
1214
token->EC[1] = (padlength >> 0) & 0xFF;
1215
} else {
1216
/*
1217
* In Wrap tokens without confidentiality, the EC field is
1218
* used to encode the size (in bytes) of the trailing
1219
* checksum.
1220
*
1221
* This is not used in the checksum calcuation itself,
1222
* because the checksum length could potentially vary
1223
* depending on the data length.
1224
*/
1225
token->EC[0] = 0;
1226
token->EC[1] = 0;
1227
}
1228
1229
/*
1230
* In Wrap tokens that provide for confidentiality, the RRC
1231
* field in the header contains the hex value 00 00 before
1232
* encryption.
1233
*
1234
* In Wrap tokens that do not provide for confidentiality,
1235
* both the EC and RRC fields in the appended checksum
1236
* contain the hex value 00 00 for the purpose of calculating
1237
* the checksum.
1238
*/
1239
token->RRC[0] = 0;
1240
token->RRC[1] = 0;
1241
1242
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1243
krb5_auth_con_getlocalseqnumber(context,
1244
ctx->auth_context,
1245
&seq_number);
1246
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1247
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1248
krb5_auth_con_setlocalseqnumber(context,
1249
ctx->auth_context,
1250
++seq_number);
1251
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1252
1253
/*
1254
* If confidentiality is requested, the token header is
1255
* appended to the plaintext before encryption; the resulting
1256
* token is {"header" | encrypt(plaintext | pad | "header")}.
1257
*
1258
* If no confidentiality is requested, the checksum is
1259
* calculated over the plaintext concatenated with the
1260
* token header.
1261
*/
1262
if (ctx->more_flags & LOCAL) {
1263
usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1264
} else {
1265
usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1266
}
1267
1268
if (conf_req_flag) {
1269
/*
1270
* Any necessary padding is added here to ensure that the
1271
* encrypted token header is always at the end of the
1272
* ciphertext.
1273
*
1274
* The specification does not require that the padding
1275
* bytes are initialized.
1276
*/
1277
p += sizeof(*token);
1278
memcpy(p, input_message_buffer->value, input_message_buffer->length);
1279
memset(p + input_message_buffer->length, 0xFF, padlength);
1280
memcpy(p + input_message_buffer->length + padlength,
1281
token, sizeof(*token));
1282
1283
ret = krb5_encrypt(context, ctx->crypto,
1284
usage, p,
1285
input_message_buffer->length + padlength +
1286
sizeof(*token),
1287
&cipher);
1288
if (ret != 0) {
1289
*minor_status = ret;
1290
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1291
return GSS_S_FAILURE;
1292
}
1293
assert(sizeof(*token) + cipher.length == wrapped_len);
1294
token->RRC[0] = (rrc >> 8) & 0xFF;
1295
token->RRC[1] = (rrc >> 0) & 0xFF;
1296
1297
/*
1298
* this is really ugly, but needed against windows
1299
* for DCERPC, as windows rotates by EC+RRC.
1300
*/
1301
if (IS_DCE_STYLE(ctx)) {
1302
ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
1303
} else {
1304
ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
1305
}
1306
if (ret != 0) {
1307
*minor_status = ret;
1308
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1309
return GSS_S_FAILURE;
1310
}
1311
memcpy(p, cipher.data, cipher.length);
1312
krb5_data_free(&cipher);
1313
} else {
1314
char *buf;
1315
Checksum cksum;
1316
1317
buf = malloc(input_message_buffer->length + sizeof(*token));
1318
if (buf == NULL) {
1319
*minor_status = ENOMEM;
1320
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1321
return GSS_S_FAILURE;
1322
}
1323
memcpy(buf, input_message_buffer->value, input_message_buffer->length);
1324
memcpy(buf + input_message_buffer->length, token, sizeof(*token));
1325
1326
ret = krb5_create_checksum(context, ctx->crypto,
1327
usage, 0, buf,
1328
input_message_buffer->length +
1329
sizeof(*token),
1330
&cksum);
1331
if (ret != 0) {
1332
*minor_status = ret;
1333
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1334
free(buf);
1335
return GSS_S_FAILURE;
1336
}
1337
1338
free(buf);
1339
1340
assert(cksum.checksum.length == cksumsize);
1341
token->EC[0] = (cksum.checksum.length >> 8) & 0xFF;
1342
token->EC[1] = (cksum.checksum.length >> 0) & 0xFF;
1343
token->RRC[0] = (rrc >> 8) & 0xFF;
1344
token->RRC[1] = (rrc >> 0) & 0xFF;
1345
1346
p += sizeof(*token);
1347
memcpy(p, input_message_buffer->value, input_message_buffer->length);
1348
memcpy(p + input_message_buffer->length,
1349
cksum.checksum.data, cksum.checksum.length);
1350
1351
ret = rrc_rotate(p,
1352
input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
1353
if (ret != 0) {
1354
*minor_status = ret;
1355
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1356
free_Checksum(&cksum);
1357
return GSS_S_FAILURE;
1358
}
1359
free_Checksum(&cksum);
1360
}
1361
1362
if (conf_state != NULL) {
1363
*conf_state = conf_req_flag;
1364
}
1365
1366
*minor_status = 0;
1367
return GSS_S_COMPLETE;
1368
}
1369
1370
OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
1371
const gsskrb5_ctx ctx,
1372
krb5_context context,
1373
const gss_buffer_t input_message_buffer,
1374
gss_buffer_t output_message_buffer,
1375
int *conf_state,
1376
gss_qop_t *qop_state)
1377
{
1378
gss_cfx_wrap_token token;
1379
u_char token_flags;
1380
krb5_error_code ret;
1381
unsigned usage;
1382
krb5_data data;
1383
uint16_t ec, rrc;
1384
OM_uint32 seq_number_lo, seq_number_hi;
1385
size_t len;
1386
u_char *p;
1387
1388
*minor_status = 0;
1389
1390
if (input_message_buffer->length < sizeof(*token)) {
1391
return GSS_S_DEFECTIVE_TOKEN;
1392
}
1393
1394
p = input_message_buffer->value;
1395
1396
token = (gss_cfx_wrap_token)p;
1397
1398
if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
1399
return GSS_S_DEFECTIVE_TOKEN;
1400
}
1401
1402
/* Ignore unknown flags */
1403
token_flags = token->Flags &
1404
(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
1405
1406
if (token_flags & CFXSentByAcceptor) {
1407
if ((ctx->more_flags & LOCAL) == 0)
1408
return GSS_S_DEFECTIVE_TOKEN;
1409
}
1410
1411
if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1412
if ((token_flags & CFXAcceptorSubkey) == 0)
1413
return GSS_S_DEFECTIVE_TOKEN;
1414
} else {
1415
if (token_flags & CFXAcceptorSubkey)
1416
return GSS_S_DEFECTIVE_TOKEN;
1417
}
1418
1419
if (token->Filler != 0xFF) {
1420
return GSS_S_DEFECTIVE_TOKEN;
1421
}
1422
1423
if (conf_state != NULL) {
1424
*conf_state = (token_flags & CFXSealed) ? 1 : 0;
1425
}
1426
1427
ec = (token->EC[0] << 8) | token->EC[1];
1428
rrc = (token->RRC[0] << 8) | token->RRC[1];
1429
1430
/*
1431
* Check sequence number
1432
*/
1433
_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1434
_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1435
if (seq_number_hi) {
1436
/* no support for 64-bit sequence numbers */
1437
*minor_status = ERANGE;
1438
return GSS_S_UNSEQ_TOKEN;
1439
}
1440
1441
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1442
ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1443
if (ret != 0) {
1444
*minor_status = 0;
1445
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1446
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1447
return ret;
1448
}
1449
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1450
1451
/*
1452
* Decrypt and/or verify checksum
1453
*/
1454
1455
if (ctx->more_flags & LOCAL) {
1456
usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1457
} else {
1458
usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1459
}
1460
1461
p += sizeof(*token);
1462
len = input_message_buffer->length;
1463
len -= (p - (u_char *)input_message_buffer->value);
1464
1465
if (token_flags & CFXSealed) {
1466
/*
1467
* this is really ugly, but needed against windows
1468
* for DCERPC, as windows rotates by EC+RRC.
1469
*/
1470
if (IS_DCE_STYLE(ctx)) {
1471
*minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
1472
} else {
1473
*minor_status = rrc_rotate(p, len, rrc, TRUE);
1474
}
1475
if (*minor_status != 0) {
1476
return GSS_S_FAILURE;
1477
}
1478
1479
ret = krb5_decrypt(context, ctx->crypto, usage,
1480
p, len, &data);
1481
if (ret != 0) {
1482
*minor_status = ret;
1483
return GSS_S_BAD_MIC;
1484
}
1485
1486
/* Check that there is room for the pad and token header */
1487
if (data.length < ec + sizeof(*token)) {
1488
krb5_data_free(&data);
1489
return GSS_S_DEFECTIVE_TOKEN;
1490
}
1491
p = data.data;
1492
p += data.length - sizeof(*token);
1493
1494
/* RRC is unprotected; don't modify input buffer */
1495
((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
1496
((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
1497
1498
/* Check the integrity of the header */
1499
if (ct_memcmp(p, token, sizeof(*token)) != 0) {
1500
krb5_data_free(&data);
1501
return GSS_S_BAD_MIC;
1502
}
1503
1504
output_message_buffer->value = data.data;
1505
output_message_buffer->length = data.length - ec - sizeof(*token);
1506
} else {
1507
Checksum cksum;
1508
1509
/* Rotate by RRC; bogus to do this in-place XXX */
1510
*minor_status = rrc_rotate(p, len, rrc, TRUE);
1511
if (*minor_status != 0) {
1512
return GSS_S_FAILURE;
1513
}
1514
1515
/* Determine checksum type */
1516
ret = krb5_crypto_get_checksum_type(context,
1517
ctx->crypto,
1518
&cksum.cksumtype);
1519
if (ret != 0) {
1520
*minor_status = ret;
1521
return GSS_S_FAILURE;
1522
}
1523
1524
cksum.checksum.length = ec;
1525
1526
/* Check we have at least as much data as the checksum */
1527
if (len < cksum.checksum.length) {
1528
*minor_status = ERANGE;
1529
return GSS_S_BAD_MIC;
1530
}
1531
1532
/* Length now is of the plaintext only, no checksum */
1533
len -= cksum.checksum.length;
1534
cksum.checksum.data = p + len;
1535
1536
output_message_buffer->length = len; /* for later */
1537
output_message_buffer->value = malloc(len + sizeof(*token));
1538
if (output_message_buffer->value == NULL) {
1539
*minor_status = ENOMEM;
1540
return GSS_S_FAILURE;
1541
}
1542
1543
/* Checksum is over (plaintext-data | "header") */
1544
memcpy(output_message_buffer->value, p, len);
1545
memcpy((u_char *)output_message_buffer->value + len,
1546
token, sizeof(*token));
1547
1548
/* EC is not included in checksum calculation */
1549
token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
1550
len);
1551
token->EC[0] = 0;
1552
token->EC[1] = 0;
1553
token->RRC[0] = 0;
1554
token->RRC[1] = 0;
1555
1556
ret = krb5_verify_checksum(context, ctx->crypto,
1557
usage,
1558
output_message_buffer->value,
1559
len + sizeof(*token),
1560
&cksum);
1561
if (ret != 0) {
1562
*minor_status = ret;
1563
_gsskrb5_release_buffer(minor_status, output_message_buffer);
1564
return GSS_S_BAD_MIC;
1565
}
1566
}
1567
1568
if (qop_state != NULL) {
1569
*qop_state = GSS_C_QOP_DEFAULT;
1570
}
1571
1572
*minor_status = 0;
1573
return GSS_S_COMPLETE;
1574
}
1575
1576
OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
1577
const gsskrb5_ctx ctx,
1578
krb5_context context,
1579
gss_qop_t qop_req,
1580
const gss_buffer_t message_buffer,
1581
gss_buffer_t message_token)
1582
{
1583
gss_cfx_mic_token token;
1584
krb5_error_code ret;
1585
unsigned usage;
1586
Checksum cksum;
1587
u_char *buf;
1588
size_t len;
1589
int32_t seq_number;
1590
1591
len = message_buffer->length + sizeof(*token);
1592
buf = malloc(len);
1593
if (buf == NULL) {
1594
*minor_status = ENOMEM;
1595
return GSS_S_FAILURE;
1596
}
1597
1598
memcpy(buf, message_buffer->value, message_buffer->length);
1599
1600
token = (gss_cfx_mic_token)(buf + message_buffer->length);
1601
token->TOK_ID[0] = 0x04;
1602
token->TOK_ID[1] = 0x04;
1603
token->Flags = 0;
1604
if ((ctx->more_flags & LOCAL) == 0)
1605
token->Flags |= CFXSentByAcceptor;
1606
if (ctx->more_flags & ACCEPTOR_SUBKEY)
1607
token->Flags |= CFXAcceptorSubkey;
1608
memset(token->Filler, 0xFF, 5);
1609
1610
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1611
krb5_auth_con_getlocalseqnumber(context,
1612
ctx->auth_context,
1613
&seq_number);
1614
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1615
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1616
krb5_auth_con_setlocalseqnumber(context,
1617
ctx->auth_context,
1618
++seq_number);
1619
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1620
1621
if (ctx->more_flags & LOCAL) {
1622
usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1623
} else {
1624
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1625
}
1626
1627
ret = krb5_create_checksum(context, ctx->crypto,
1628
usage, 0, buf, len, &cksum);
1629
if (ret != 0) {
1630
*minor_status = ret;
1631
free(buf);
1632
return GSS_S_FAILURE;
1633
}
1634
1635
/* Determine MIC length */
1636
message_token->length = sizeof(*token) + cksum.checksum.length;
1637
message_token->value = malloc(message_token->length);
1638
if (message_token->value == NULL) {
1639
*minor_status = ENOMEM;
1640
free_Checksum(&cksum);
1641
free(buf);
1642
return GSS_S_FAILURE;
1643
}
1644
1645
/* Token is { "header" | get_mic("header" | plaintext-data) } */
1646
memcpy(message_token->value, token, sizeof(*token));
1647
memcpy((u_char *)message_token->value + sizeof(*token),
1648
cksum.checksum.data, cksum.checksum.length);
1649
1650
free_Checksum(&cksum);
1651
free(buf);
1652
1653
*minor_status = 0;
1654
return GSS_S_COMPLETE;
1655
}
1656
1657
OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
1658
const gsskrb5_ctx ctx,
1659
krb5_context context,
1660
const gss_buffer_t message_buffer,
1661
const gss_buffer_t token_buffer,
1662
gss_qop_t *qop_state)
1663
{
1664
gss_cfx_mic_token token;
1665
u_char token_flags;
1666
krb5_error_code ret;
1667
unsigned usage;
1668
OM_uint32 seq_number_lo, seq_number_hi;
1669
u_char *buf, *p;
1670
Checksum cksum;
1671
1672
*minor_status = 0;
1673
1674
if (token_buffer->length < sizeof(*token)) {
1675
return GSS_S_DEFECTIVE_TOKEN;
1676
}
1677
1678
p = token_buffer->value;
1679
1680
token = (gss_cfx_mic_token)p;
1681
1682
if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
1683
return GSS_S_DEFECTIVE_TOKEN;
1684
}
1685
1686
/* Ignore unknown flags */
1687
token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
1688
1689
if (token_flags & CFXSentByAcceptor) {
1690
if ((ctx->more_flags & LOCAL) == 0)
1691
return GSS_S_DEFECTIVE_TOKEN;
1692
}
1693
if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1694
if ((token_flags & CFXAcceptorSubkey) == 0)
1695
return GSS_S_DEFECTIVE_TOKEN;
1696
} else {
1697
if (token_flags & CFXAcceptorSubkey)
1698
return GSS_S_DEFECTIVE_TOKEN;
1699
}
1700
1701
if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
1702
return GSS_S_DEFECTIVE_TOKEN;
1703
}
1704
1705
/*
1706
* Check sequence number
1707
*/
1708
_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1709
_gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1710
if (seq_number_hi) {
1711
*minor_status = ERANGE;
1712
return GSS_S_UNSEQ_TOKEN;
1713
}
1714
1715
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1716
ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1717
if (ret != 0) {
1718
*minor_status = 0;
1719
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1720
return ret;
1721
}
1722
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1723
1724
/*
1725
* Verify checksum
1726
*/
1727
ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
1728
&cksum.cksumtype);
1729
if (ret != 0) {
1730
*minor_status = ret;
1731
return GSS_S_FAILURE;
1732
}
1733
1734
cksum.checksum.data = p + sizeof(*token);
1735
cksum.checksum.length = token_buffer->length - sizeof(*token);
1736
1737
if (ctx->more_flags & LOCAL) {
1738
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1739
} else {
1740
usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1741
}
1742
1743
buf = malloc(message_buffer->length + sizeof(*token));
1744
if (buf == NULL) {
1745
*minor_status = ENOMEM;
1746
return GSS_S_FAILURE;
1747
}
1748
memcpy(buf, message_buffer->value, message_buffer->length);
1749
memcpy(buf + message_buffer->length, token, sizeof(*token));
1750
1751
ret = krb5_verify_checksum(context, ctx->crypto,
1752
usage,
1753
buf,
1754
sizeof(*token) + message_buffer->length,
1755
&cksum);
1756
if (ret != 0) {
1757
*minor_status = ret;
1758
free(buf);
1759
return GSS_S_BAD_MIC;
1760
}
1761
1762
free(buf);
1763
1764
if (qop_state != NULL) {
1765
*qop_state = GSS_C_QOP_DEFAULT;
1766
}
1767
1768
return GSS_S_COMPLETE;
1769
}
1770
1771