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