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