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 564967 : _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 564967 : *output_length = sizeof(gss_cfx_wrap_token_desc);
58 564967 : *padlength = 0;
59 :
60 564967 : ret = krb5_crypto_get_checksum_type(context, crypto, &type);
61 564967 : if (ret)
62 0 : return ret;
63 :
64 564967 : ret = krb5_checksumsize(context, type, cksumsize);
65 564967 : if (ret)
66 0 : return ret;
67 :
68 564967 : if (conf_req_flag) {
69 : size_t padsize;
70 :
71 : /* Header is concatenated with data before encryption */
72 564375 : input_length += sizeof(gss_cfx_wrap_token_desc);
73 :
74 564375 : if (dce_style) {
75 0 : ret = krb5_crypto_getblocksize(context, crypto, &padsize);
76 : } else {
77 564375 : ret = krb5_crypto_getpadsize(context, crypto, &padsize);
78 : }
79 564375 : if (ret) {
80 0 : return ret;
81 : }
82 564375 : 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 564375 : *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 564967 : assert(*output_length > input_length);
98 :
99 564967 : return 0;
100 : }
101 :
102 : OM_uint32
103 18449 : _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 18449 : *max_input_size = 0;
114 :
115 : /* 16-byte header is always first */
116 18449 : if (req_output_size < 16)
117 0 : return 0;
118 18449 : req_output_size -= 16;
119 :
120 18449 : if (conf_req_flag) {
121 : size_t wrapped_size, sz;
122 :
123 18289 : wrapped_size = req_output_size + 1;
124 : do {
125 530381 : wrapped_size--;
126 530381 : sz = krb5_get_wrapped_length(context,
127 : ctx->crypto, wrapped_size);
128 530381 : } while (wrapped_size && sz > req_output_size);
129 18289 : if (wrapped_size == 0)
130 0 : return 0;
131 :
132 : /* inner header */
133 18289 : if (wrapped_size < 16)
134 0 : return 0;
135 :
136 18289 : wrapped_size -= 16;
137 :
138 18289 : *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 18449 : return 0;
159 : }
160 :
161 : /*
162 : * Rotate "rrc" bytes to the front or back
163 : */
164 :
165 : static krb5_error_code
166 1129934 : 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 1129934 : if (len == 0)
172 0 : return 0;
173 :
174 1129934 : rrc %= len;
175 :
176 1129934 : if (rrc == 0)
177 0 : return 0;
178 :
179 1129934 : left = len - rrc;
180 :
181 1129934 : if (rrc <= sizeof(buf)) {
182 1129934 : tmp = buf;
183 : } else {
184 0 : tmp = malloc(rrc);
185 0 : if (tmp == NULL)
186 0 : return ENOMEM;
187 : }
188 :
189 1129934 : if (unrotate) {
190 564967 : memcpy(tmp, data, rrc);
191 564967 : memmove(data, (u_char *)data + rrc, left);
192 564967 : memcpy((u_char *)data + left, tmp, rrc);
193 : } else {
194 564967 : memcpy(tmp, (u_char *)data + left, rrc);
195 564967 : memmove((u_char *)data + rrc, data, left);
196 564967 : memcpy(data, tmp, rrc);
197 : }
198 :
199 1129934 : if (rrc > sizeof(buf))
200 0 : free(tmp);
201 :
202 1129934 : return 0;
203 : }
204 :
205 : gss_iov_buffer_desc *
206 4270323 : _gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
207 : {
208 : int i;
209 4270323 : gss_iov_buffer_t iovp = GSS_C_NO_IOV_BUFFER;
210 :
211 4270323 : 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 21351615 : for (i = 0; i < iov_count; i++) {
219 17081292 : if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) {
220 1423441 : if (iovp == GSS_C_NO_IOV_BUFFER)
221 1423441 : 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 5693764 : if (iovp &&
233 1423441 : 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 4270323 : 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 1437226 : _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 1437226 : if (header == NULL) {
271 0 : *minor_status = EINVAL;
272 0 : return GSS_S_FAILURE;
273 : }
274 :
275 1437226 : if (IS_DCE_STYLE(ctx)) {
276 : /*
277 : * In DCE style mode we reject having a padding or trailer buffer
278 : */
279 1437226 : if (padding) {
280 0 : *minor_status = EINVAL;
281 0 : return GSS_S_FAILURE;
282 : }
283 1437226 : 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 1437226 : *minor_status = 0;
301 1437226 : return GSS_S_COMPLETE;
302 : }
303 :
304 : OM_uint32
305 1058310 : _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 1058310 : 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 1058310 : krb5_crypto_iov *data = NULL;
324 :
325 1058310 : header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
326 1058310 : if (header == NULL) {
327 0 : *minor_status = EINVAL;
328 0 : return GSS_S_FAILURE;
329 : }
330 :
331 1058310 : padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
332 1058310 : if (padding != NULL) {
333 0 : padding->buffer.length = 0;
334 : }
335 :
336 1058310 : trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
337 :
338 1058310 : major_status = _gk_verify_buffers(minor_status, ctx, header,
339 : padding, trailer, FALSE);
340 1058310 : if (major_status != GSS_S_COMPLETE) {
341 0 : return major_status;
342 : }
343 :
344 1058310 : if (conf_req_flag) {
345 1058310 : size_t k5psize = 0;
346 1058310 : size_t k5pbase = 0;
347 1058310 : size_t k5bsize = 0;
348 1058310 : size_t size = 0;
349 :
350 5291550 : for (i = 0; i < iov_count; i++) {
351 4233240 : switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
352 1058310 : case GSS_IOV_BUFFER_TYPE_DATA:
353 1058310 : size += iov[i].buffer.length;
354 1058310 : break;
355 3174930 : default:
356 3174930 : break;
357 : }
358 : }
359 :
360 1058310 : size += sizeof(gss_cfx_wrap_token_desc);
361 :
362 1058310 : *minor_status = krb5_crypto_length(context, ctx->crypto,
363 : KRB5_CRYPTO_TYPE_HEADER,
364 : &k5hsize);
365 1058310 : if (*minor_status)
366 0 : return GSS_S_FAILURE;
367 :
368 1058310 : *minor_status = krb5_crypto_length(context, ctx->crypto,
369 : KRB5_CRYPTO_TYPE_TRAILER,
370 : &k5tsize);
371 1058310 : if (*minor_status)
372 0 : return GSS_S_FAILURE;
373 :
374 1058310 : *minor_status = krb5_crypto_length(context, ctx->crypto,
375 : KRB5_CRYPTO_TYPE_PADDING,
376 : &k5pbase);
377 1058310 : if (*minor_status)
378 0 : return GSS_S_FAILURE;
379 :
380 1058310 : if (k5pbase > 1) {
381 0 : k5psize = k5pbase - (size % k5pbase);
382 : } else {
383 1058310 : k5psize = 0;
384 : }
385 :
386 1058310 : if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
387 1058310 : *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
388 : &k5bsize);
389 1058310 : if (*minor_status)
390 0 : return GSS_S_FAILURE;
391 1058310 : ec = k5bsize;
392 : } else {
393 0 : ec = k5psize;
394 : }
395 :
396 1058310 : gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
397 1058310 : 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 1058310 : if (trailer == NULL) {
420 1058310 : rrc = gsstsize;
421 1058310 : if (IS_DCE_STYLE(ctx))
422 1058310 : rrc -= ec;
423 1058310 : 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 1058310 : 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 1058310 : } 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 1058310 : header->buffer.length = gsshsize;
449 :
450 1058310 : token = (gss_cfx_wrap_token)header->buffer.value;
451 :
452 1058310 : token->TOK_ID[0] = 0x05;
453 1058310 : token->TOK_ID[1] = 0x04;
454 1058310 : token->Flags = 0;
455 1058310 : token->Filler = 0xFF;
456 :
457 1058310 : if ((ctx->more_flags & LOCAL) == 0)
458 1032241 : token->Flags |= CFXSentByAcceptor;
459 :
460 1058310 : if (ctx->more_flags & ACCEPTOR_SUBKEY)
461 1058310 : token->Flags |= CFXAcceptorSubkey;
462 :
463 1058310 : if (ctx->more_flags & LOCAL)
464 26069 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
465 : else
466 1032241 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
467 :
468 1058310 : 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 1058310 : token->Flags |= CFXSealed;
474 1058310 : token->EC[0] = (ec >> 8) & 0xFF;
475 1058310 : 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 1058310 : token->RRC[0] = 0;
502 1058310 : token->RRC[1] = 0;
503 :
504 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
505 1058310 : krb5_auth_con_getlocalseqnumber(context,
506 : ctx->auth_context,
507 : &seq_number);
508 1058310 : _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
509 1058310 : _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
510 1058310 : krb5_auth_con_setlocalseqnumber(context,
511 : ctx->auth_context,
512 : ++seq_number);
513 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
514 :
515 1058310 : data = calloc(iov_count + 3, sizeof(data[0]));
516 1058310 : if (data == NULL) {
517 0 : *minor_status = ENOMEM;
518 0 : major_status = GSS_S_FAILURE;
519 0 : goto failure;
520 : }
521 :
522 1058310 : 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 1058310 : i = 0;
538 1058310 : data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
539 1058310 : data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
540 1058310 : data[i].data.length = k5hsize;
541 :
542 5291550 : for (i = 1; i < iov_count + 1; i++) {
543 4233240 : switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
544 1058310 : case GSS_IOV_BUFFER_TYPE_DATA:
545 1058310 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
546 1058310 : break;
547 2093206 : case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
548 2093206 : data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
549 2093206 : break;
550 1081724 : default:
551 1081724 : data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
552 1081724 : break;
553 : }
554 4233240 : data[i].data.length = iov[i - 1].buffer.length;
555 4233240 : 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 1058310 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
568 1058310 : if (trailer)
569 0 : data[i].data.data = trailer->buffer.value;
570 : else
571 1058310 : data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
572 :
573 1058310 : data[i].data.length = ec + sizeof(*token);
574 1058310 : memset(data[i].data.data, 0xFF, ec);
575 1058310 : memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
576 1058310 : i++;
577 :
578 : /* Kerberos trailer comes after the gss trailer */
579 1058310 : data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
580 1058310 : data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
581 1058310 : data[i].data.length = k5tsize;
582 1058310 : i++;
583 :
584 1058310 : ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
585 1058310 : if (ret != 0) {
586 0 : *minor_status = ret;
587 0 : major_status = GSS_S_FAILURE;
588 0 : goto failure;
589 : }
590 :
591 1058310 : if (rrc) {
592 1058310 : token->RRC[0] = (rrc >> 8) & 0xFF;
593 1058310 : 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 1058310 : if (conf_state != NULL)
654 1058310 : *conf_state = conf_req_flag;
655 :
656 1058310 : free(data);
657 :
658 1058310 : *minor_status = 0;
659 1058310 : 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 336833 : _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 336833 : krb5_crypto_iov *data = NULL;
759 : int i, j;
760 :
761 336833 : *minor_status = 0;
762 :
763 336833 : header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
764 336833 : if (header == NULL) {
765 0 : *minor_status = EINVAL;
766 0 : return GSS_S_FAILURE;
767 : }
768 :
769 336833 : if (header->buffer.length < sizeof(*token)) /* we check exact below */
770 0 : return GSS_S_DEFECTIVE_TOKEN;
771 :
772 336833 : padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
773 336833 : if (padding != NULL && padding->buffer.length != 0) {
774 0 : *minor_status = EINVAL;
775 0 : return GSS_S_FAILURE;
776 : }
777 :
778 336833 : trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
779 :
780 336833 : major_status = _gk_verify_buffers(minor_status, ctx, header,
781 : padding, trailer, FALSE);
782 336833 : if (major_status != GSS_S_COMPLETE) {
783 0 : return major_status;
784 : }
785 :
786 336833 : token = (gss_cfx_wrap_token)header->buffer.value;
787 :
788 336833 : if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
789 0 : return GSS_S_DEFECTIVE_TOKEN;
790 :
791 : /* Ignore unknown flags */
792 336833 : token_flags = token->Flags &
793 : (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
794 :
795 336833 : if (token_flags & CFXSentByAcceptor) {
796 215707 : if ((ctx->more_flags & LOCAL) == 0)
797 0 : return GSS_S_DEFECTIVE_TOKEN;
798 : }
799 :
800 336833 : if (ctx->more_flags & ACCEPTOR_SUBKEY) {
801 336833 : 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 336833 : if (token->Filler != 0xFF)
809 0 : return GSS_S_DEFECTIVE_TOKEN;
810 :
811 336833 : if (conf_state != NULL)
812 336833 : *conf_state = (token_flags & CFXSealed) ? 1 : 0;
813 :
814 336833 : ec = (token->EC[0] << 8) | token->EC[1];
815 336833 : rrc = (token->RRC[0] << 8) | token->RRC[1];
816 :
817 : /*
818 : * Check sequence number
819 : */
820 336833 : _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
821 336833 : _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
822 336833 : 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 336833 : ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
830 336833 : 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 336833 : if (ctx->more_flags & LOCAL) {
842 215707 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
843 : } else {
844 121126 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
845 : }
846 :
847 336833 : data = calloc(iov_count + 3, sizeof(data[0]));
848 336833 : if (data == NULL) {
849 0 : *minor_status = ENOMEM;
850 0 : major_status = GSS_S_FAILURE;
851 0 : goto failure;
852 : }
853 :
854 336833 : if (token_flags & CFXSealed) {
855 : size_t k5tsize, k5hsize;
856 :
857 336833 : krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
858 336833 : 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 336833 : if (trailer == NULL) {
864 336833 : size_t gsstsize = k5tsize + sizeof(*token);
865 336833 : size_t gsshsize = k5hsize + sizeof(*token);
866 :
867 336833 : if (rrc != gsstsize) {
868 0 : major_status = GSS_S_DEFECTIVE_TOKEN;
869 0 : goto failure;
870 : }
871 :
872 336833 : if (IS_DCE_STYLE(ctx))
873 336833 : gsstsize += ec;
874 :
875 336833 : gsshsize += gsstsize;
876 :
877 336833 : 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 336833 : i = 0;
895 336833 : data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
896 336833 : data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
897 336833 : data[i].data.length = k5hsize;
898 336833 : i++;
899 :
900 1684165 : for (j = 0; j < iov_count; i++, j++) {
901 1347332 : switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
902 336833 : case GSS_IOV_BUFFER_TYPE_DATA:
903 336833 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
904 336833 : break;
905 650224 : case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
906 650224 : data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
907 650224 : break;
908 360275 : default:
909 360275 : data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
910 360275 : break;
911 : }
912 1347332 : data[i].data.length = iov[j].buffer.length;
913 1347332 : 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 336833 : data[i].flags = KRB5_CRYPTO_TYPE_DATA;
920 336833 : if (trailer) {
921 0 : data[i].data.data = trailer->buffer.value;
922 : } else {
923 1010499 : data[i].data.data = ((uint8_t *)header->buffer.value) +
924 673666 : header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
925 : }
926 :
927 336833 : data[i].data.length = ec + sizeof(*token);
928 336833 : ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
929 336833 : i++;
930 :
931 : /* Kerberos trailer comes after the gss trailer */
932 336833 : data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
933 336833 : data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
934 336833 : data[i].data.length = k5tsize;
935 336833 : i++;
936 :
937 336833 : ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
938 336833 : if (ret != 0) {
939 0 : *minor_status = ret;
940 0 : major_status = GSS_S_FAILURE;
941 0 : goto failure;
942 : }
943 :
944 336833 : ttoken->RRC[0] = token->RRC[0];
945 336833 : ttoken->RRC[1] = token->RRC[1];
946 :
947 : /* Check the integrity of the header */
948 336833 : 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 336833 : if (qop_state != NULL) {
1026 336833 : *qop_state = GSS_C_QOP_DEFAULT;
1027 : }
1028 :
1029 336833 : free(data);
1030 :
1031 336833 : *minor_status = 0;
1032 336833 : 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 13157 : _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 13157 : gss_iov_buffer_desc *header = NULL;
1057 13157 : gss_iov_buffer_desc *padding = NULL;
1058 13157 : gss_iov_buffer_desc *trailer = NULL;
1059 13157 : size_t gsshsize = 0;
1060 13157 : size_t gsstsize = 0;
1061 13157 : size_t k5hsize = 0;
1062 13157 : size_t k5tsize = 0;
1063 :
1064 13157 : GSSAPI_KRB5_INIT (&context);
1065 13157 : *minor_status = 0;
1066 :
1067 39471 : for (size = 0, i = 0; i < iov_count; i++) {
1068 26314 : switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1069 0 : case GSS_IOV_BUFFER_TYPE_EMPTY:
1070 0 : break;
1071 13157 : case GSS_IOV_BUFFER_TYPE_DATA:
1072 13157 : size += iov[i].buffer.length;
1073 13157 : break;
1074 13157 : case GSS_IOV_BUFFER_TYPE_HEADER:
1075 13157 : if (header != NULL) {
1076 0 : *minor_status = 0;
1077 0 : return GSS_S_FAILURE;
1078 : }
1079 13157 : header = &iov[i];
1080 13157 : 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 13157 : major_status = _gk_verify_buffers(minor_status, ctx, header,
1104 : padding, trailer, FALSE);
1105 13157 : if (major_status != GSS_S_COMPLETE) {
1106 0 : return major_status;
1107 : }
1108 :
1109 13157 : if (conf_req_flag) {
1110 13157 : size_t k5psize = 0;
1111 13157 : size_t k5pbase = 0;
1112 13157 : size_t k5bsize = 0;
1113 13157 : size_t ec = 0;
1114 :
1115 13157 : size += sizeof(gss_cfx_wrap_token_desc);
1116 :
1117 13157 : *minor_status = krb5_crypto_length(context, ctx->crypto,
1118 : KRB5_CRYPTO_TYPE_HEADER,
1119 : &k5hsize);
1120 13157 : if (*minor_status)
1121 0 : return GSS_S_FAILURE;
1122 :
1123 13157 : *minor_status = krb5_crypto_length(context, ctx->crypto,
1124 : KRB5_CRYPTO_TYPE_TRAILER,
1125 : &k5tsize);
1126 13157 : if (*minor_status)
1127 0 : return GSS_S_FAILURE;
1128 :
1129 13157 : *minor_status = krb5_crypto_length(context, ctx->crypto,
1130 : KRB5_CRYPTO_TYPE_PADDING,
1131 : &k5pbase);
1132 13157 : if (*minor_status)
1133 0 : return GSS_S_FAILURE;
1134 :
1135 13157 : if (k5pbase > 1) {
1136 0 : k5psize = k5pbase - (size % k5pbase);
1137 : } else {
1138 13157 : k5psize = 0;
1139 : }
1140 :
1141 13157 : if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
1142 13157 : *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
1143 : &k5bsize);
1144 13157 : if (*minor_status)
1145 0 : return GSS_S_FAILURE;
1146 :
1147 13157 : ec = k5bsize;
1148 : } else {
1149 0 : ec = k5psize;
1150 : }
1151 :
1152 13157 : gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
1153 13157 : 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 13157 : if (trailer != NULL) {
1166 0 : trailer->buffer.length = gsstsize;
1167 : } else {
1168 13157 : gsshsize += gsstsize;
1169 : }
1170 :
1171 13157 : header->buffer.length = gsshsize;
1172 :
1173 13157 : 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 13157 : if (conf_state) {
1179 13157 : *conf_state = conf_req_flag;
1180 : }
1181 :
1182 13157 : return GSS_S_COMPLETE;
1183 : }
1184 :
1185 :
1186 :
1187 :
1188 564967 : 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 564967 : uint16_t padlength, rrc = 0;
1202 : int32_t seq_number;
1203 : u_char *p;
1204 :
1205 564967 : 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 564967 : 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 564967 : rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
1217 :
1218 564967 : output_message_buffer->length = wrapped_len;
1219 564967 : output_message_buffer->value = malloc(output_message_buffer->length);
1220 564967 : if (output_message_buffer->value == NULL) {
1221 0 : *minor_status = ENOMEM;
1222 0 : return GSS_S_FAILURE;
1223 : }
1224 :
1225 564967 : p = output_message_buffer->value;
1226 564967 : token = (gss_cfx_wrap_token)p;
1227 564967 : token->TOK_ID[0] = 0x05;
1228 564967 : token->TOK_ID[1] = 0x04;
1229 564967 : token->Flags = 0;
1230 564967 : token->Filler = 0xFF;
1231 564967 : if ((ctx->more_flags & LOCAL) == 0)
1232 285131 : token->Flags |= CFXSentByAcceptor;
1233 564967 : if (ctx->more_flags & ACCEPTOR_SUBKEY)
1234 564967 : token->Flags |= CFXAcceptorSubkey;
1235 564967 : 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 564375 : token->Flags |= CFXSealed;
1241 564375 : token->EC[0] = (padlength >> 8) & 0xFF;
1242 564375 : 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 564967 : token->RRC[0] = 0;
1268 564967 : token->RRC[1] = 0;
1269 :
1270 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1271 564967 : krb5_auth_con_getlocalseqnumber(context,
1272 : ctx->auth_context,
1273 : &seq_number);
1274 564967 : _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1275 564967 : _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1276 564967 : 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 564967 : if (ctx->more_flags & LOCAL) {
1291 279836 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1292 : } else {
1293 285131 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1294 : }
1295 :
1296 564967 : 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 564375 : p += sizeof(*token);
1306 564375 : memcpy(p, input_message_buffer->value, input_message_buffer->length);
1307 564375 : memset(p + input_message_buffer->length, 0xFF, padlength);
1308 564375 : memcpy(p + input_message_buffer->length + padlength,
1309 : token, sizeof(*token));
1310 :
1311 564375 : ret = krb5_encrypt(context, ctx->crypto,
1312 : usage, p,
1313 564375 : input_message_buffer->length + padlength +
1314 : sizeof(*token),
1315 : &cipher);
1316 564375 : 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 564375 : assert(sizeof(*token) + cipher.length == wrapped_len);
1322 564375 : token->RRC[0] = (rrc >> 8) & 0xFF;
1323 564375 : 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 564375 : if (IS_DCE_STYLE(ctx)) {
1330 0 : ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
1331 : } else {
1332 564375 : ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
1333 : }
1334 564375 : 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 564375 : memcpy(p, cipher.data, cipher.length);
1340 564375 : 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 1184 : memcpy(p + input_message_buffer->length,
1377 592 : cksum.checksum.data, cksum.checksum.length);
1378 :
1379 1184 : 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 564967 : if (conf_state != NULL) {
1391 564967 : *conf_state = conf_req_flag;
1392 : }
1393 :
1394 564967 : *minor_status = 0;
1395 564967 : return GSS_S_COMPLETE;
1396 : }
1397 :
1398 564967 : 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 564967 : *minor_status = 0;
1417 :
1418 564967 : if (input_message_buffer->length < sizeof(*token)) {
1419 0 : return GSS_S_DEFECTIVE_TOKEN;
1420 : }
1421 :
1422 564967 : p = input_message_buffer->value;
1423 :
1424 564967 : token = (gss_cfx_wrap_token)p;
1425 :
1426 564967 : 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 564967 : token_flags = token->Flags &
1432 : (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
1433 :
1434 564967 : if (token_flags & CFXSentByAcceptor) {
1435 285068 : if ((ctx->more_flags & LOCAL) == 0)
1436 0 : return GSS_S_DEFECTIVE_TOKEN;
1437 : }
1438 :
1439 564967 : if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1440 564967 : 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 564967 : if (token->Filler != 0xFF) {
1448 0 : return GSS_S_DEFECTIVE_TOKEN;
1449 : }
1450 :
1451 564967 : if (conf_state != NULL) {
1452 564967 : *conf_state = (token_flags & CFXSealed) ? 1 : 0;
1453 : }
1454 :
1455 564967 : ec = (token->EC[0] << 8) | token->EC[1];
1456 564967 : rrc = (token->RRC[0] << 8) | token->RRC[1];
1457 :
1458 : /*
1459 : * Check sequence number
1460 : */
1461 564967 : _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1462 564967 : _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1463 564967 : 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 564967 : ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1471 564967 : 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 564967 : if (ctx->more_flags & LOCAL) {
1484 285068 : usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1485 : } else {
1486 279899 : usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1487 : }
1488 :
1489 564967 : p += sizeof(*token);
1490 564967 : len = input_message_buffer->length;
1491 564967 : len -= (p - (u_char *)input_message_buffer->value);
1492 :
1493 564967 : 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 564375 : if (IS_DCE_STYLE(ctx)) {
1499 0 : *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
1500 : } else {
1501 564375 : *minor_status = rrc_rotate(p, len, rrc, TRUE);
1502 : }
1503 564375 : if (*minor_status != 0) {
1504 0 : return GSS_S_FAILURE;
1505 : }
1506 :
1507 564375 : ret = krb5_decrypt(context, ctx->crypto, usage,
1508 : p, len, &data);
1509 564375 : 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 564375 : if (data.length < ec + sizeof(*token)) {
1516 0 : krb5_data_free(&data);
1517 0 : return GSS_S_DEFECTIVE_TOKEN;
1518 : }
1519 564375 : p = data.data;
1520 564375 : p += data.length - sizeof(*token);
1521 :
1522 : /* RRC is unprotected; don't modify input buffer */
1523 564375 : ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
1524 564375 : ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
1525 :
1526 : /* Check the integrity of the header */
1527 564375 : if (ct_memcmp(p, token, sizeof(*token)) != 0) {
1528 0 : krb5_data_free(&data);
1529 0 : return GSS_S_BAD_MIC;
1530 : }
1531 :
1532 564375 : output_message_buffer->value = data.data;
1533 564375 : 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 564967 : if (qop_state != NULL) {
1597 564967 : *qop_state = GSS_C_QOP_DEFAULT;
1598 : }
1599 :
1600 564967 : *minor_status = 0;
1601 564967 : return GSS_S_COMPLETE;
1602 : }
1603 :
1604 168017 : 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 168017 : len = message_buffer->length + sizeof(*token);
1620 168017 : buf = malloc(len);
1621 168017 : if (buf == NULL) {
1622 0 : *minor_status = ENOMEM;
1623 0 : return GSS_S_FAILURE;
1624 : }
1625 :
1626 168017 : memcpy(buf, message_buffer->value, message_buffer->length);
1627 :
1628 168017 : token = (gss_cfx_mic_token)(buf + message_buffer->length);
1629 168017 : token->TOK_ID[0] = 0x04;
1630 168017 : token->TOK_ID[1] = 0x04;
1631 168017 : token->Flags = 0;
1632 168017 : if ((ctx->more_flags & LOCAL) == 0)
1633 151603 : token->Flags |= CFXSentByAcceptor;
1634 168017 : if (ctx->more_flags & ACCEPTOR_SUBKEY)
1635 168017 : token->Flags |= CFXAcceptorSubkey;
1636 168017 : memset(token->Filler, 0xFF, 5);
1637 :
1638 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1639 168017 : krb5_auth_con_getlocalseqnumber(context,
1640 : ctx->auth_context,
1641 : &seq_number);
1642 168017 : _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1643 168017 : _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1644 168017 : krb5_auth_con_setlocalseqnumber(context,
1645 : ctx->auth_context,
1646 : ++seq_number);
1647 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1648 :
1649 168017 : if (ctx->more_flags & LOCAL) {
1650 16414 : usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1651 : } else {
1652 151603 : usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1653 : }
1654 :
1655 168017 : ret = krb5_create_checksum(context, ctx->crypto,
1656 : usage, 0, buf, len, &cksum);
1657 168017 : 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 168017 : message_token->length = sizeof(*token) + cksum.checksum.length;
1665 168017 : message_token->value = malloc(message_token->length);
1666 168017 : 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 168017 : memcpy(message_token->value, token, sizeof(*token));
1675 336034 : memcpy((u_char *)message_token->value + sizeof(*token),
1676 168017 : cksum.checksum.data, cksum.checksum.length);
1677 :
1678 168017 : free_Checksum(&cksum);
1679 168017 : free(buf);
1680 :
1681 168017 : *minor_status = 0;
1682 168017 : return GSS_S_COMPLETE;
1683 : }
1684 :
1685 168143 : 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 168143 : *minor_status = 0;
1701 :
1702 168143 : if (token_buffer->length < sizeof(*token)) {
1703 1 : return GSS_S_DEFECTIVE_TOKEN;
1704 : }
1705 :
1706 168142 : p = token_buffer->value;
1707 :
1708 168142 : token = (gss_cfx_mic_token)p;
1709 :
1710 168142 : 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 168142 : token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
1716 :
1717 168142 : if (token_flags & CFXSentByAcceptor) {
1718 16311 : if ((ctx->more_flags & LOCAL) == 0)
1719 0 : return GSS_S_DEFECTIVE_TOKEN;
1720 : }
1721 168142 : if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1722 168142 : 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 168142 : 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 168142 : _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1737 168142 : _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1738 168142 : 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 168142 : ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1745 168142 : 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 168142 : ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
1756 : &cksum.cksumtype);
1757 168142 : if (ret != 0) {
1758 0 : *minor_status = ret;
1759 0 : return GSS_S_FAILURE;
1760 : }
1761 :
1762 168142 : cksum.checksum.data = p + sizeof(*token);
1763 168142 : cksum.checksum.length = token_buffer->length - sizeof(*token);
1764 :
1765 168142 : if (ctx->more_flags & LOCAL) {
1766 16311 : usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1767 : } else {
1768 151831 : usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1769 : }
1770 :
1771 168142 : buf = malloc(message_buffer->length + sizeof(*token));
1772 168142 : if (buf == NULL) {
1773 0 : *minor_status = ENOMEM;
1774 0 : return GSS_S_FAILURE;
1775 : }
1776 168142 : memcpy(buf, message_buffer->value, message_buffer->length);
1777 168142 : memcpy(buf + message_buffer->length, token, sizeof(*token));
1778 :
1779 168142 : ret = krb5_verify_checksum(context, ctx->crypto,
1780 : usage,
1781 : buf,
1782 168142 : sizeof(*token) + message_buffer->length,
1783 : &cksum);
1784 168142 : if (ret != 0) {
1785 20 : *minor_status = ret;
1786 20 : free(buf);
1787 20 : return GSS_S_BAD_MIC;
1788 : }
1789 :
1790 168122 : free(buf);
1791 :
1792 168122 : if (qop_state != NULL) {
1793 168122 : *qop_state = GSS_C_QOP_DEFAULT;
1794 : }
1795 :
1796 168122 : return GSS_S_COMPLETE;
1797 : }
|