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