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 676148 : _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 676148 : *output_length = sizeof(gss_cfx_wrap_token_desc);
58 676148 : *padlength = 0;
59 :
60 676148 : ret = krb5_crypto_get_checksum_type(context, crypto, &type);
61 676148 : if (ret)
62 0 : return ret;
63 :
64 676148 : ret = krb5_checksumsize(context, type, cksumsize);
65 676148 : if (ret)
66 0 : return ret;
67 :
68 676148 : if (conf_req_flag) {
69 930 : size_t padsize;
70 :
71 : /* Header is concatenated with data before encryption */
72 675494 : input_length += sizeof(gss_cfx_wrap_token_desc);
73 :
74 675494 : if (dce_style) {
75 0 : ret = krb5_crypto_getblocksize(context, crypto, &padsize);
76 : } else {
77 675494 : ret = krb5_crypto_getpadsize(context, crypto, &padsize);
78 : }
79 675494 : if (ret) {
80 0 : return ret;
81 : }
82 675494 : 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 675494 : *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 676148 : assert(*output_length > input_length);
98 :
99 675218 : return 0;
100 : }
101 :
102 : OM_uint32
103 23787 : _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 23787 : *max_input_size = 0;
114 :
115 : /* 16-byte header is always first */
116 23787 : if (req_output_size < 16)
117 0 : return 0;
118 23787 : req_output_size -= 16;
119 :
120 23787 : if (conf_req_flag) {
121 244 : size_t wrapped_size, sz;
122 :
123 23625 : wrapped_size = req_output_size + 1;
124 7076 : do {
125 685125 : wrapped_size--;
126 685125 : sz = krb5_get_wrapped_length(context,
127 : ctx->crypto, wrapped_size);
128 685125 : } while (wrapped_size && sz > req_output_size);
129 23625 : if (wrapped_size == 0)
130 0 : return 0;
131 :
132 : /* inner header */
133 23625 : if (wrapped_size < 16)
134 0 : return 0;
135 :
136 23625 : wrapped_size -= 16;
137 :
138 23625 : *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 23543 : return 0;
159 : }
160 :
161 : /*
162 : * Rotate "rrc" bytes to the front or back
163 : */
164 :
165 : static krb5_error_code
166 1352152 : 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 1352152 : if (len == 0)
172 0 : return 0;
173 :
174 1352152 : rrc %= len;
175 :
176 1352152 : if (rrc == 0)
177 0 : return 0;
178 :
179 1352152 : left = len - rrc;
180 :
181 1352152 : if (rrc <= sizeof(buf)) {
182 1350292 : tmp = buf;
183 : } else {
184 0 : tmp = malloc(rrc);
185 0 : if (tmp == NULL)
186 0 : return ENOMEM;
187 : }
188 :
189 1352152 : if (unrotate) {
190 676004 : memcpy(tmp, data, rrc);
191 676004 : memmove(data, (u_char *)data + rrc, left);
192 676004 : memcpy((u_char *)data + left, tmp, rrc);
193 : } else {
194 676148 : memcpy(tmp, (u_char *)data + left, rrc);
195 676148 : memmove((u_char *)data + rrc, data, left);
196 676148 : memcpy(data, tmp, rrc);
197 : }
198 :
199 1352152 : if (rrc > sizeof(buf))
200 0 : free(tmp);
201 :
202 1350292 : return 0;
203 : }
204 :
205 : gss_iov_buffer_desc *
206 4796586 : _gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
207 : {
208 7875 : int i;
209 4796586 : gss_iov_buffer_t iovp = GSS_C_NO_IOV_BUFFER;
210 :
211 4796586 : 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 23982930 : for (i = 0; i < iov_count; i++) {
219 19186344 : if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) {
220 1598862 : if (iovp == GSS_C_NO_IOV_BUFFER)
221 1596237 : 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 4796586 : if (iovp &&
233 1598862 : 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 4788711 : 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 1614487 : _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 1614487 : if (header == NULL) {
271 0 : *minor_status = EINVAL;
272 0 : return GSS_S_FAILURE;
273 : }
274 :
275 1614487 : if (IS_DCE_STYLE(ctx)) {
276 : /*
277 : * In DCE style mode we reject having a padding or trailer buffer
278 : */
279 1614487 : 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 1614487 : *minor_status = 0;
297 1614487 : return GSS_S_COMPLETE;
298 : }
299 :
300 : OM_uint32
301 1142895 : _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 1142895 : 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 1142895 : krb5_crypto_iov *data = NULL;
320 :
321 1142895 : header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
322 1142895 : if (header == NULL) {
323 0 : *minor_status = EINVAL;
324 0 : return GSS_S_FAILURE;
325 : }
326 :
327 1142895 : padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
328 1142895 : if (padding != NULL) {
329 0 : padding->buffer.length = 0;
330 : }
331 :
332 1142895 : trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
333 :
334 1142895 : major_status = _gk_verify_buffers(minor_status, ctx, header,
335 : padding, trailer, FALSE);
336 1142895 : if (major_status != GSS_S_COMPLETE) {
337 0 : return major_status;
338 : }
339 :
340 1142895 : if (conf_req_flag) {
341 1142895 : size_t k5psize = 0;
342 1142895 : size_t k5pbase = 0;
343 1142895 : size_t k5bsize = 0;
344 1142895 : size_t size = 0;
345 :
346 5714475 : for (i = 0; i < iov_count; i++) {
347 4571580 : switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
348 1142895 : case GSS_IOV_BUFFER_TYPE_DATA:
349 1142895 : size += iov[i].buffer.length;
350 1142895 : break;
351 3424746 : default:
352 3424746 : break;
353 : }
354 : }
355 :
356 1142895 : size += sizeof(gss_cfx_wrap_token_desc);
357 :
358 1142895 : *minor_status = krb5_crypto_length(context, ctx->crypto,
359 : KRB5_CRYPTO_TYPE_HEADER,
360 : &k5hsize);
361 1142895 : if (*minor_status)
362 0 : return GSS_S_FAILURE;
363 :
364 1142895 : *minor_status = krb5_crypto_length(context, ctx->crypto,
365 : KRB5_CRYPTO_TYPE_TRAILER,
366 : &k5tsize);
367 1142895 : if (*minor_status)
368 0 : return GSS_S_FAILURE;
369 :
370 1142895 : *minor_status = krb5_crypto_length(context, ctx->crypto,
371 : KRB5_CRYPTO_TYPE_PADDING,
372 : &k5pbase);
373 1142895 : if (*minor_status)
374 0 : return GSS_S_FAILURE;
375 :
376 1142895 : if (k5pbase > 1) {
377 0 : k5psize = k5pbase - (size % k5pbase);
378 : } else {
379 1141582 : k5psize = 0;
380 : }
381 :
382 1142895 : if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
383 1142895 : *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
384 : &k5bsize);
385 1142895 : if (*minor_status)
386 0 : return GSS_S_FAILURE;
387 1142895 : ec = k5bsize;
388 : } else {
389 0 : ec = k5psize;
390 : }
391 :
392 1142895 : gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
393 1142895 : 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 1142895 : if (trailer == NULL) {
416 1142895 : rrc = gsstsize;
417 1142895 : if (IS_DCE_STYLE(ctx))
418 1142895 : rrc -= ec;
419 1142895 : 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 1142895 : 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 1142895 : } 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 1142895 : header->buffer.length = gsshsize;
445 :
446 1142895 : token = (gss_cfx_wrap_token)header->buffer.value;
447 :
448 1142895 : token->TOK_ID[0] = 0x05;
449 1142895 : token->TOK_ID[1] = 0x04;
450 1142895 : token->Flags = 0;
451 1142895 : token->Filler = 0xFF;
452 :
453 1142895 : if ((ctx->more_flags & LOCAL) == 0)
454 1113488 : token->Flags |= CFXSentByAcceptor;
455 :
456 1142895 : if (ctx->more_flags & ACCEPTOR_SUBKEY)
457 1142895 : token->Flags |= CFXAcceptorSubkey;
458 :
459 1142895 : if (ctx->more_flags & LOCAL)
460 28741 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
461 : else
462 1113488 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
463 :
464 1142895 : 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 1142895 : token->Flags |= CFXSealed;
470 1142895 : token->EC[0] = (ec >> 8) & 0xFF;
471 1142895 : 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 1142895 : token->RRC[0] = 0;
498 1142895 : token->RRC[1] = 0;
499 :
500 1313 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
501 1142895 : krb5_auth_con_getlocalseqnumber(context,
502 : ctx->auth_context,
503 : &seq_number);
504 1142895 : _gss_mg_encode_be_uint32(0, &token->SND_SEQ[0]);
505 1142895 : _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]);
506 1142895 : krb5_auth_con_setlocalseqnumber(context,
507 : ctx->auth_context,
508 : ++seq_number);
509 1313 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
510 :
511 1142895 : data = calloc(iov_count + 3, sizeof(data[0]));
512 1142895 : if (data == NULL) {
513 0 : *minor_status = ENOMEM;
514 0 : major_status = GSS_S_FAILURE;
515 0 : goto failure;
516 : }
517 :
518 1142895 : 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 1142895 : i = 0;
534 1142895 : data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
535 1142895 : data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
536 1142895 : data[i].data.length = k5hsize;
537 :
538 5714475 : for (i = 1; i < iov_count + 1; i++) {
539 4571580 : switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
540 1142895 : case GSS_IOV_BUFFER_TYPE_DATA:
541 1142895 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
542 1142895 : break;
543 2260534 : case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
544 2260534 : data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
545 2260534 : break;
546 1168151 : default:
547 1168151 : data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
548 1168151 : break;
549 : }
550 4571580 : data[i].data.length = iov[i - 1].buffer.length;
551 4571580 : 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 1142895 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
564 1142895 : if (trailer)
565 0 : data[i].data.data = trailer->buffer.value;
566 : else
567 1142895 : data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
568 :
569 1142895 : data[i].data.length = ec + sizeof(*token);
570 1142895 : memset(data[i].data.data, 0xFF, ec);
571 1142895 : memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
572 1142895 : i++;
573 :
574 : /* Kerberos trailer comes after the gss trailer */
575 1142895 : data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
576 1142895 : data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
577 1142895 : data[i].data.length = k5tsize;
578 1142895 : i++;
579 :
580 1142895 : ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
581 1142895 : if (ret != 0) {
582 0 : *minor_status = ret;
583 0 : major_status = GSS_S_FAILURE;
584 0 : goto failure;
585 : }
586 :
587 1142895 : if (rrc) {
588 1142895 : token->RRC[0] = (rrc >> 8) & 0xFF;
589 1142895 : 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 1142895 : if (conf_state != NULL)
650 1142895 : *conf_state = conf_req_flag;
651 :
652 1142895 : free(data);
653 :
654 1142895 : *minor_status = 0;
655 1142895 : 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 426371 : _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 426371 : krb5_crypto_iov *data = NULL;
755 1312 : int i, j;
756 :
757 426371 : *minor_status = 0;
758 :
759 426371 : header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
760 426371 : if (header == NULL) {
761 0 : *minor_status = EINVAL;
762 0 : return GSS_S_FAILURE;
763 : }
764 :
765 426371 : if (header->buffer.length < sizeof(*token)) /* we check exact below */
766 0 : return GSS_S_DEFECTIVE_TOKEN;
767 :
768 426371 : padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
769 426371 : if (padding != NULL && padding->buffer.length != 0) {
770 0 : *minor_status = EINVAL;
771 0 : return GSS_S_FAILURE;
772 : }
773 :
774 426371 : trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
775 :
776 426371 : major_status = _gk_verify_buffers(minor_status, ctx, header,
777 : padding, trailer, FALSE);
778 426371 : if (major_status != GSS_S_COMPLETE) {
779 0 : return major_status;
780 : }
781 :
782 426371 : token = (gss_cfx_wrap_token)header->buffer.value;
783 :
784 426371 : if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
785 0 : return GSS_S_DEFECTIVE_TOKEN;
786 :
787 : /* Ignore unknown flags */
788 426371 : token_flags = token->Flags &
789 : (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
790 :
791 426371 : if (token_flags & CFXSentByAcceptor) {
792 270224 : if ((ctx->more_flags & LOCAL) == 0)
793 0 : return GSS_S_DEFECTIVE_TOKEN;
794 : }
795 :
796 426371 : if (ctx->more_flags & ACCEPTOR_SUBKEY) {
797 426371 : 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 426371 : if (token->Filler != 0xFF)
805 0 : return GSS_S_DEFECTIVE_TOKEN;
806 :
807 426371 : if (conf_state != NULL)
808 426371 : *conf_state = (token_flags & CFXSealed) ? 1 : 0;
809 :
810 426371 : ec = (token->EC[0] << 8) | token->EC[1];
811 426371 : rrc = (token->RRC[0] << 8) | token->RRC[1];
812 :
813 : /*
814 : * Check sequence number
815 : */
816 426371 : _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi);
817 426371 : _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo);
818 426371 : 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 426371 : ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
826 426371 : 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 426371 : if (ctx->more_flags & LOCAL) {
838 269577 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
839 : } else {
840 156147 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
841 : }
842 :
843 426371 : data = calloc(iov_count + 3, sizeof(data[0]));
844 426371 : if (data == NULL) {
845 0 : *minor_status = ENOMEM;
846 0 : major_status = GSS_S_FAILURE;
847 0 : goto failure;
848 : }
849 :
850 426371 : if (token_flags & CFXSealed) {
851 1312 : size_t k5tsize, k5hsize;
852 :
853 426371 : krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
854 426371 : 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 426371 : if (trailer == NULL) {
860 426371 : size_t gsstsize = k5tsize + sizeof(*token);
861 426371 : size_t gsshsize = k5hsize + sizeof(*token);
862 :
863 426371 : if (rrc != gsstsize) {
864 0 : major_status = GSS_S_DEFECTIVE_TOKEN;
865 0 : goto failure;
866 : }
867 :
868 426371 : if (IS_DCE_STYLE(ctx))
869 426371 : gsstsize += ec;
870 :
871 426371 : gsshsize += gsstsize;
872 :
873 426371 : 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 426371 : i = 0;
891 426371 : data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
892 426371 : data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
893 426371 : data[i].data.length = k5hsize;
894 426371 : i++;
895 :
896 2131855 : for (j = 0; j < iov_count; i++, j++) {
897 1705484 : switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
898 426371 : case GSS_IOV_BUFFER_TYPE_DATA:
899 426371 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
900 426371 : break;
901 827472 : case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
902 827472 : data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
903 827472 : break;
904 451641 : default:
905 451641 : data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
906 451641 : break;
907 : }
908 1705484 : data[i].data.length = iov[j].buffer.length;
909 1705484 : 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 426371 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
916 426371 : if (trailer) {
917 0 : data[i].data.data = trailer->buffer.value;
918 : } else {
919 426371 : data[i].data.data = ((uint8_t *)header->buffer.value) +
920 426371 : header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
921 : }
922 :
923 426371 : data[i].data.length = ec + sizeof(*token);
924 426371 : ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
925 426371 : i++;
926 :
927 : /* Kerberos trailer comes after the gss trailer */
928 426371 : data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
929 426371 : data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
930 426371 : data[i].data.length = k5tsize;
931 426371 : i++;
932 :
933 426371 : ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
934 426371 : if (ret != 0) {
935 0 : *minor_status = ret;
936 0 : major_status = GSS_S_FAILURE;
937 0 : goto failure;
938 : }
939 :
940 426371 : ttoken->RRC[0] = token->RRC[0];
941 426371 : ttoken->RRC[1] = token->RRC[1];
942 :
943 : /* Check the integrity of the header */
944 426371 : 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 426371 : if (qop_state != NULL) {
1022 426371 : *qop_state = GSS_C_QOP_DEFAULT;
1023 : }
1024 :
1025 426371 : free(data);
1026 :
1027 426371 : *minor_status = 0;
1028 426371 : 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 14997 : _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 14997 : gss_iov_buffer_desc *header = NULL;
1053 14997 : gss_iov_buffer_desc *padding = NULL;
1054 14997 : gss_iov_buffer_desc *trailer = NULL;
1055 14997 : size_t gsshsize = 0;
1056 14997 : size_t gsstsize = 0;
1057 14997 : size_t k5hsize = 0;
1058 14997 : size_t k5tsize = 0;
1059 :
1060 14997 : GSSAPI_KRB5_INIT (&context);
1061 14997 : *minor_status = 0;
1062 :
1063 44991 : for (size = 0, i = 0; i < iov_count; i++) {
1064 29994 : switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1065 0 : case GSS_IOV_BUFFER_TYPE_EMPTY:
1066 0 : break;
1067 14997 : case GSS_IOV_BUFFER_TYPE_DATA:
1068 14997 : size += iov[i].buffer.length;
1069 14997 : break;
1070 14997 : case GSS_IOV_BUFFER_TYPE_HEADER:
1071 14997 : if (header != NULL) {
1072 0 : *minor_status = 0;
1073 0 : return GSS_S_FAILURE;
1074 : }
1075 14813 : header = &iov[i];
1076 14813 : 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 14997 : major_status = _gk_verify_buffers(minor_status, ctx, header,
1100 : padding, trailer, FALSE);
1101 14997 : if (major_status != GSS_S_COMPLETE) {
1102 0 : return major_status;
1103 : }
1104 :
1105 14997 : if (conf_req_flag) {
1106 14997 : size_t k5psize = 0;
1107 14997 : size_t k5pbase = 0;
1108 14997 : size_t k5bsize = 0;
1109 14997 : size_t ec = 0;
1110 :
1111 14997 : size += sizeof(gss_cfx_wrap_token_desc);
1112 :
1113 14997 : *minor_status = krb5_crypto_length(context, ctx->crypto,
1114 : KRB5_CRYPTO_TYPE_HEADER,
1115 : &k5hsize);
1116 14997 : if (*minor_status)
1117 0 : return GSS_S_FAILURE;
1118 :
1119 14997 : *minor_status = krb5_crypto_length(context, ctx->crypto,
1120 : KRB5_CRYPTO_TYPE_TRAILER,
1121 : &k5tsize);
1122 14997 : if (*minor_status)
1123 0 : return GSS_S_FAILURE;
1124 :
1125 14997 : *minor_status = krb5_crypto_length(context, ctx->crypto,
1126 : KRB5_CRYPTO_TYPE_PADDING,
1127 : &k5pbase);
1128 14997 : if (*minor_status)
1129 0 : return GSS_S_FAILURE;
1130 :
1131 14997 : if (k5pbase > 1) {
1132 0 : k5psize = k5pbase - (size % k5pbase);
1133 : } else {
1134 14813 : k5psize = 0;
1135 : }
1136 :
1137 14997 : if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
1138 14997 : *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
1139 : &k5bsize);
1140 14997 : if (*minor_status)
1141 0 : return GSS_S_FAILURE;
1142 :
1143 14997 : ec = k5bsize;
1144 : } else {
1145 0 : ec = k5psize;
1146 : }
1147 :
1148 14997 : gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
1149 14997 : 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 14997 : if (trailer != NULL) {
1162 0 : trailer->buffer.length = gsstsize;
1163 : } else {
1164 14997 : gsshsize += gsstsize;
1165 : }
1166 :
1167 14997 : header->buffer.length = gsshsize;
1168 :
1169 14997 : 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 14997 : if (conf_state) {
1175 14997 : *conf_state = conf_req_flag;
1176 : }
1177 :
1178 14813 : return GSS_S_COMPLETE;
1179 : }
1180 :
1181 :
1182 :
1183 :
1184 676148 : 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 676148 : uint16_t padlength, rrc = 0;
1198 930 : int32_t seq_number;
1199 930 : u_char *p;
1200 :
1201 676148 : 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 676148 : 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 676148 : rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
1213 :
1214 676148 : output_message_buffer->length = wrapped_len;
1215 676148 : output_message_buffer->value = malloc(output_message_buffer->length);
1216 676148 : if (output_message_buffer->value == NULL) {
1217 0 : *minor_status = ENOMEM;
1218 0 : return GSS_S_FAILURE;
1219 : }
1220 :
1221 676148 : p = output_message_buffer->value;
1222 676148 : token = (gss_cfx_wrap_token)p;
1223 676148 : token->TOK_ID[0] = 0x05;
1224 676148 : token->TOK_ID[1] = 0x04;
1225 676148 : token->Flags = 0;
1226 676148 : token->Filler = 0xFF;
1227 676148 : if ((ctx->more_flags & LOCAL) == 0)
1228 340733 : token->Flags |= CFXSentByAcceptor;
1229 676148 : if (ctx->more_flags & ACCEPTOR_SUBKEY)
1230 676148 : token->Flags |= CFXAcceptorSubkey;
1231 676148 : 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 675494 : token->Flags |= CFXSealed;
1237 675494 : token->EC[0] = (padlength >> 8) & 0xFF;
1238 675494 : 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 676148 : token->RRC[0] = 0;
1264 676148 : token->RRC[1] = 0;
1265 :
1266 930 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1267 676148 : krb5_auth_con_getlocalseqnumber(context,
1268 : ctx->auth_context,
1269 : &seq_number);
1270 676148 : _gss_mg_encode_be_uint32(0, &token->SND_SEQ[0]);
1271 676148 : _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]);
1272 676148 : 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 676148 : if (ctx->more_flags & LOCAL) {
1287 334950 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1288 : } else {
1289 340733 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1290 : }
1291 :
1292 676148 : 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 675494 : p += sizeof(*token);
1302 675494 : memcpy(p, input_message_buffer->value, input_message_buffer->length);
1303 675494 : memset(p + input_message_buffer->length, 0xFF, padlength);
1304 675494 : memcpy(p + input_message_buffer->length + padlength,
1305 : token, sizeof(*token));
1306 :
1307 676424 : ret = krb5_encrypt(context, ctx->crypto,
1308 : usage, p,
1309 675494 : input_message_buffer->length + padlength +
1310 : sizeof(*token),
1311 : &cipher);
1312 675494 : 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 675494 : assert(sizeof(*token) + cipher.length == wrapped_len);
1318 675494 : token->RRC[0] = (rrc >> 8) & 0xFF;
1319 675494 : 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 675494 : if (IS_DCE_STYLE(ctx)) {
1326 0 : ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
1327 : } else {
1328 675494 : ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
1329 : }
1330 675494 : 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 675494 : memcpy(p, cipher.data, cipher.length);
1336 675494 : 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 676148 : if (conf_state != NULL) {
1387 676148 : *conf_state = conf_req_flag;
1388 : }
1389 :
1390 676148 : *minor_status = 0;
1391 676148 : return GSS_S_COMPLETE;
1392 : }
1393 :
1394 676004 : 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 676004 : *minor_status = 0;
1413 :
1414 676004 : if (input_message_buffer->length < sizeof(*token)) {
1415 0 : return GSS_S_DEFECTIVE_TOKEN;
1416 : }
1417 :
1418 676004 : p = input_message_buffer->value;
1419 :
1420 676004 : token = (gss_cfx_wrap_token)p;
1421 :
1422 676004 : 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 676004 : token_flags = token->Flags &
1428 : (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
1429 :
1430 676004 : if (token_flags & CFXSentByAcceptor) {
1431 340529 : if ((ctx->more_flags & LOCAL) == 0)
1432 0 : return GSS_S_DEFECTIVE_TOKEN;
1433 : }
1434 :
1435 676004 : if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1436 676004 : 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 676004 : if (token->Filler != 0xFF) {
1444 0 : return GSS_S_DEFECTIVE_TOKEN;
1445 : }
1446 :
1447 676004 : if (conf_state != NULL) {
1448 676004 : *conf_state = (token_flags & CFXSealed) ? 1 : 0;
1449 : }
1450 :
1451 676004 : ec = (token->EC[0] << 8) | token->EC[1];
1452 676004 : rrc = (token->RRC[0] << 8) | token->RRC[1];
1453 :
1454 : /*
1455 : * Check sequence number
1456 : */
1457 676004 : _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi);
1458 676004 : _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo);
1459 676004 : 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 676004 : ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1467 676004 : 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 676004 : if (ctx->more_flags & LOCAL) {
1480 340064 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1481 : } else {
1482 335475 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1483 : }
1484 :
1485 676004 : p += sizeof(*token);
1486 676004 : len = input_message_buffer->length;
1487 676004 : len -= (p - (u_char *)input_message_buffer->value);
1488 :
1489 676004 : 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 675350 : if (IS_DCE_STYLE(ctx)) {
1495 0 : *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
1496 : } else {
1497 675350 : *minor_status = rrc_rotate(p, len, rrc, TRUE);
1498 : }
1499 675350 : if (*minor_status != 0) {
1500 0 : return GSS_S_FAILURE;
1501 : }
1502 :
1503 675350 : ret = krb5_decrypt(context, ctx->crypto, usage,
1504 : p, len, &data);
1505 675350 : 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 675350 : if (data.length < ec + sizeof(*token)) {
1512 0 : krb5_data_free(&data);
1513 0 : return GSS_S_DEFECTIVE_TOKEN;
1514 : }
1515 675350 : p = data.data;
1516 675350 : p += data.length - sizeof(*token);
1517 :
1518 : /* RRC is unprotected; don't modify input buffer */
1519 675350 : ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
1520 675350 : ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
1521 :
1522 : /* Check the integrity of the header */
1523 675350 : if (ct_memcmp(p, token, sizeof(*token)) != 0) {
1524 0 : krb5_data_free(&data);
1525 0 : return GSS_S_BAD_MIC;
1526 : }
1527 :
1528 675350 : output_message_buffer->value = data.data;
1529 675350 : 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 676004 : if (qop_state != NULL) {
1593 676004 : *qop_state = GSS_C_QOP_DEFAULT;
1594 : }
1595 :
1596 676004 : *minor_status = 0;
1597 676004 : return GSS_S_COMPLETE;
1598 : }
1599 :
1600 233592 : 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 233592 : len = message_buffer->length + sizeof(*token);
1616 233592 : buf = malloc(len);
1617 233592 : if (buf == NULL) {
1618 0 : *minor_status = ENOMEM;
1619 0 : return GSS_S_FAILURE;
1620 : }
1621 :
1622 233592 : if (message_buffer->length)
1623 233472 : memcpy(buf, message_buffer->value, message_buffer->length);
1624 : else
1625 120 : memset(buf, 0, len);
1626 :
1627 233592 : token = (gss_cfx_mic_token)(buf + message_buffer->length);
1628 233592 : token->TOK_ID[0] = 0x04;
1629 233592 : token->TOK_ID[1] = 0x04;
1630 233592 : token->Flags = 0;
1631 233592 : if ((ctx->more_flags & LOCAL) == 0)
1632 215003 : token->Flags |= CFXSentByAcceptor;
1633 233592 : if (ctx->more_flags & ACCEPTOR_SUBKEY)
1634 233592 : token->Flags |= CFXAcceptorSubkey;
1635 233592 : memset(token->Filler, 0xFF, 5);
1636 :
1637 317 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1638 233592 : krb5_auth_con_getlocalseqnumber(context,
1639 : ctx->auth_context,
1640 : &seq_number);
1641 233592 : _gss_mg_encode_be_uint32(0, &token->SND_SEQ[0]);
1642 233592 : _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]);
1643 233592 : krb5_auth_con_setlocalseqnumber(context,
1644 : ctx->auth_context,
1645 : ++seq_number);
1646 317 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1647 :
1648 233592 : if (ctx->more_flags & LOCAL) {
1649 18430 : usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1650 : } else {
1651 215003 : usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1652 : }
1653 :
1654 233592 : ret = krb5_create_checksum(context, ctx->crypto,
1655 : usage, 0, buf, len, &cksum);
1656 233592 : 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 233592 : message_token->length = sizeof(*token) + cksum.checksum.length;
1664 233592 : message_token->value = malloc(message_token->length);
1665 233592 : 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 233592 : memcpy(message_token->value, token, sizeof(*token));
1674 233592 : memcpy((u_char *)message_token->value + sizeof(*token),
1675 233592 : cksum.checksum.data, cksum.checksum.length);
1676 :
1677 233592 : free_Checksum(&cksum);
1678 233592 : free(buf);
1679 :
1680 233592 : *minor_status = 0;
1681 233592 : return GSS_S_COMPLETE;
1682 : }
1683 :
1684 233870 : 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 233870 : *minor_status = 0;
1700 :
1701 233870 : if (token_buffer->length < sizeof(*token)) {
1702 1 : return GSS_S_DEFECTIVE_TOKEN;
1703 : }
1704 :
1705 233869 : p = token_buffer->value;
1706 :
1707 233869 : token = (gss_cfx_mic_token)p;
1708 :
1709 233869 : 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 233869 : token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
1715 :
1716 233869 : if (token_flags & CFXSentByAcceptor) {
1717 18464 : if ((ctx->more_flags & LOCAL) == 0)
1718 0 : return GSS_S_DEFECTIVE_TOKEN;
1719 : }
1720 233869 : if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1721 233869 : 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 233869 : 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 233869 : _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi);
1736 233869 : _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo);
1737 233869 : 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 233869 : ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1744 233869 : 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 233869 : ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
1755 : &cksum.cksumtype);
1756 233869 : if (ret != 0) {
1757 0 : *minor_status = ret;
1758 0 : return GSS_S_FAILURE;
1759 : }
1760 :
1761 233869 : cksum.checksum.data = p + sizeof(*token);
1762 233869 : cksum.checksum.length = token_buffer->length - sizeof(*token);
1763 :
1764 233869 : if (ctx->more_flags & LOCAL) {
1765 18306 : usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1766 : } else {
1767 215405 : usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1768 : }
1769 :
1770 233869 : buf = malloc(message_buffer->length + sizeof(*token));
1771 233869 : if (buf == NULL) {
1772 0 : *minor_status = ENOMEM;
1773 0 : return GSS_S_FAILURE;
1774 : }
1775 233869 : if (message_buffer->length)
1776 233791 : memcpy(buf, message_buffer->value, message_buffer->length);
1777 233869 : memcpy(buf + message_buffer->length, token, sizeof(*token));
1778 :
1779 233869 : ret = krb5_verify_checksum(context, ctx->crypto,
1780 : usage,
1781 : buf,
1782 233552 : sizeof(*token) + message_buffer->length,
1783 : &cksum);
1784 233869 : if (ret != 0) {
1785 20 : *minor_status = ret;
1786 20 : free(buf);
1787 20 : return GSS_S_BAD_MIC;
1788 : }
1789 :
1790 233849 : free(buf);
1791 :
1792 233849 : if (qop_state != NULL) {
1793 233849 : *qop_state = GSS_C_QOP_DEFAULT;
1794 : }
1795 :
1796 233532 : return GSS_S_COMPLETE;
1797 : }
|