1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
4 * Copyright 1993 by OpenVision Technologies, Inc.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software
7 * and its documentation for any purpose is hereby granted without fee,
8 * provided that the above copyright notice appears in all copies and
9 * that both that copyright notice and this permission notice appear in
10 * supporting documentation, and that the name of OpenVision not be used
11 * in advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. OpenVision makes no
13 * representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 /*
26 * Copyright (C) 1998 by the FundsXpress, INC.
27 *
28 * All rights reserved.
29 *
30 * Export of this software from the United States of America may require
31 * a specific license from the United States Government. It is the
32 * responsibility of any person or organization contemplating export to
33 * obtain such a license before exporting.
34 *
35 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
36 * distribute this software and its documentation for any purpose and
37 * without fee is hereby granted, provided that the above copyright
38 * notice appear in all copies and that both that copyright notice and
39 * this permission notice appear in supporting documentation, and that
40 * the name of FundsXpress. not be used in advertising or publicity pertaining
41 * to distribution of the software without specific, written prior
42 * permission. FundsXpress makes no representations about the suitability of
43 * this software for any purpose. It is provided "as is" without express
44 * or implied warranty.
45 *
46 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
48 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
49 */
50
51 #include "k5-int.h"
52 #include "gssapiP_krb5.h"
53 #ifdef HAVE_MEMORY_H
54 #include <memory.h>
55 #endif
56
57 static krb5_error_code
kg_copy_keys(krb5_context context,krb5_gss_ctx_id_rec * ctx,krb5_key subkey)58 kg_copy_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey)
59 {
60 krb5_error_code code;
61
62 krb5_k_free_key(context, ctx->enc);
63 ctx->enc = NULL;
64 code = krb5_k_create_key(context, &subkey->keyblock, &ctx->enc);
65 if (code != 0)
66 return code;
67
68 krb5_k_free_key(context, ctx->seq);
69 ctx->seq = NULL;
70 code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
71 if (code != 0)
72 return code;
73
74 return 0;
75 }
76
77 krb5_error_code
kg_setup_keys(krb5_context context,krb5_gss_ctx_id_rec * ctx,krb5_key subkey,krb5_cksumtype * cksumtype)78 kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
79 krb5_cksumtype *cksumtype)
80 {
81 krb5_error_code code;
82
83 assert(ctx != NULL);
84 assert(subkey != NULL);
85
86 *cksumtype = 0;
87 ctx->proto = 0;
88
89 if (ctx->enc == NULL) {
90 ctx->signalg = -1;
91 ctx->sealalg = -1;
92 }
93
94 code = krb5int_c_mandatory_cksumtype(context, subkey->keyblock.enctype,
95 cksumtype);
96 if (code != 0)
97 return code;
98
99 switch (subkey->keyblock.enctype) {
100 case ENCTYPE_DES3_CBC_SHA1:
101 code = kg_copy_keys(context, ctx, subkey);
102 if (code != 0)
103 return code;
104
105 ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
106 ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
107 ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
108 ctx->cksum_size = 20;
109 ctx->sealalg = SEAL_ALG_DES3KD;
110 break;
111 case ENCTYPE_ARCFOUR_HMAC:
112 case ENCTYPE_ARCFOUR_HMAC_EXP:
113 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer" enctype,
114 * even though RFC 4757 treats it as one. */
115 code = kg_copy_keys(context, ctx, subkey);
116 if (code != 0)
117 return code;
118
119 ctx->signalg = SGN_ALG_HMAC_MD5;
120 ctx->cksum_size = 8;
121 ctx->sealalg = SEAL_ALG_MICROSOFT_RC4;
122 break;
123 default:
124 ctx->proto = 1;
125 break;
126 }
127
128 return 0;
129 }
130
131 int
kg_confounder_size(krb5_context context,krb5_enctype enctype)132 kg_confounder_size(krb5_context context, krb5_enctype enctype)
133 {
134 krb5_error_code code;
135 size_t blocksize;
136 /* We special case rc4*/
137 if (enctype == ENCTYPE_ARCFOUR_HMAC || enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
138 return 8;
139 code = krb5_c_block_size(context, enctype, &blocksize);
140 if (code)
141 return(-1); /* XXX */
142
143 return(blocksize);
144 }
145
146 krb5_error_code
kg_make_confounder(krb5_context context,krb5_enctype enctype,unsigned char * buf)147 kg_make_confounder(krb5_context context, krb5_enctype enctype,
148 unsigned char *buf)
149 {
150 int confsize;
151 krb5_data lrandom;
152
153 confsize = kg_confounder_size(context, enctype);
154 if (confsize < 0)
155 return KRB5_BAD_MSIZE;
156
157 lrandom.length = confsize;
158 lrandom.data = (char *)buf;
159
160 return(krb5_c_random_make_octets(context, &lrandom));
161 }
162
163 /* Set *data_out to a krb5_data structure containing iv, or to NULL if iv is
164 * NULL. */
165 static krb5_error_code
iv_to_state(krb5_context context,krb5_key key,krb5_pointer iv,krb5_data ** data_out)166 iv_to_state(krb5_context context, krb5_key key, krb5_pointer iv,
167 krb5_data **data_out)
168 {
169 krb5_error_code code;
170 krb5_data *data;
171 size_t blocksize;
172
173 *data_out = NULL;
174 if (iv == NULL)
175 return 0;
176
177 code = krb5_c_block_size(context, key->keyblock.enctype, &blocksize);
178 if (code)
179 return code;
180
181 data = k5alloc(sizeof(*data), &code);
182 if (data == NULL)
183 return code;
184 code = alloc_data(data, blocksize);
185 if (code) {
186 free(data);
187 return code;
188 }
189 memcpy(data->data, iv, blocksize);
190 *data_out = data;
191 return 0;
192 }
193
194 krb5_error_code
kg_encrypt(krb5_context context,krb5_key key,int usage,krb5_pointer iv,krb5_const_pointer in,krb5_pointer out,unsigned int length)195 kg_encrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
196 krb5_const_pointer in, krb5_pointer out, unsigned int length)
197 {
198 krb5_error_code code;
199 krb5_data *state, inputd;
200 krb5_enc_data outputd;
201
202 code = iv_to_state(context, key, iv, &state);
203 if (code)
204 return code;
205
206 inputd.length = length;
207 inputd.data = (char *)in;
208
209 outputd.ciphertext.length = length;
210 outputd.ciphertext.data = out;
211
212 code = krb5_k_encrypt(context, key, usage, state, &inputd, &outputd);
213 krb5_free_data(context, state);
214 return code;
215 }
216
217 krb5_error_code
kg_encrypt_inplace(krb5_context context,krb5_key key,int usage,krb5_pointer iv,krb5_pointer ptr,unsigned int length)218 kg_encrypt_inplace(krb5_context context, krb5_key key, int usage,
219 krb5_pointer iv, krb5_pointer ptr, unsigned int length)
220 {
221 krb5_error_code code;
222 krb5_crypto_iov iov;
223 krb5_data *state;
224
225 code = iv_to_state(context, key, iv, &state);
226 if (code)
227 return code;
228
229 iov.flags = KRB5_CRYPTO_TYPE_DATA;
230 iov.data = make_data((void *)ptr, length);
231 code = krb5_k_encrypt_iov(context, key, usage, state, &iov, 1);
232 krb5_free_data(context, state);
233 return code;
234 }
235
236 /* length is the length of the cleartext. */
237
238 krb5_error_code
kg_decrypt(krb5_context context,krb5_key key,int usage,krb5_pointer iv,krb5_const_pointer in,krb5_pointer out,unsigned int length)239 kg_decrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
240 krb5_const_pointer in, krb5_pointer out, unsigned int length)
241 {
242 krb5_error_code code;
243 krb5_data *state, outputd;
244 krb5_enc_data inputd;
245
246 code = iv_to_state(context, key, iv, &state);
247 if (code)
248 return code;
249
250 inputd.enctype = ENCTYPE_UNKNOWN;
251 inputd.ciphertext.length = length;
252 inputd.ciphertext.data = (char *)in;
253
254 outputd.length = length;
255 outputd.data = out;
256
257 code = krb5_k_decrypt(context, key, usage, state, &inputd, &outputd);
258 krb5_free_data(context, state);
259 return code;
260 }
261
262 krb5_error_code
kg_arcfour_docrypt(const krb5_keyblock * keyblock,int usage,const unsigned char * kd_data,size_t kd_data_len,const unsigned char * input_buf,size_t input_len,unsigned char * output_buf)263 kg_arcfour_docrypt(const krb5_keyblock *keyblock, int usage,
264 const unsigned char *kd_data, size_t kd_data_len,
265 const unsigned char *input_buf, size_t input_len,
266 unsigned char *output_buf)
267 {
268 krb5_data kd = make_data((char *) kd_data, kd_data_len);
269 krb5_crypto_iov kiov;
270
271 memcpy(output_buf, input_buf, input_len);
272 kiov.flags = KRB5_CRYPTO_TYPE_DATA;
273 kiov.data = make_data(output_buf, input_len);
274 return krb5int_arcfour_gsscrypt(keyblock, usage, &kd, &kiov, 1);
275 }
276
277 /* AEAD */
278 static krb5_error_code
kg_translate_iov_v1(krb5_context context,krb5_enctype enctype,gss_iov_buffer_desc * iov,int iov_count,krb5_crypto_iov ** pkiov,size_t * pkiov_count)279 kg_translate_iov_v1(krb5_context context, krb5_enctype enctype,
280 gss_iov_buffer_desc *iov, int iov_count,
281 krb5_crypto_iov **pkiov, size_t *pkiov_count)
282 {
283 gss_iov_buffer_desc *header;
284 gss_iov_buffer_desc *trailer;
285 int i = 0, j;
286 size_t kiov_count;
287 krb5_crypto_iov *kiov;
288 size_t conf_len;
289
290 *pkiov = NULL;
291 *pkiov_count = 0;
292
293 conf_len = kg_confounder_size(context, enctype);
294
295 header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
296 assert(header != NULL);
297
298 if (header->buffer.length < conf_len)
299 return KRB5_BAD_MSIZE;
300
301 trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
302 assert(trailer == NULL || trailer->buffer.length == 0);
303
304 kiov_count = 3 + iov_count;
305 kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
306 if (kiov == NULL)
307 return ENOMEM;
308
309 /* For pre-CFX (raw enctypes) there is no krb5 header */
310 kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
311 kiov[i].data.length = 0;
312 kiov[i].data.data = NULL;
313 i++;
314
315 /* For pre-CFX, the confounder is at the end of the GSS header */
316 kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
317 kiov[i].data.length = conf_len;
318 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
319 i++;
320
321 for (j = 0; j < iov_count; j++) {
322 kiov[i].flags = kg_translate_flag_iov(iov[j].type);
323 if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
324 continue;
325
326 kiov[i].data.length = iov[j].buffer.length;
327 kiov[i].data.data = (char *)iov[j].buffer.value;
328 i++;
329 }
330
331 kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
332 kiov[i].data.length = 0;
333 kiov[i].data.data = NULL;
334 i++;
335
336 *pkiov = kiov;
337 *pkiov_count = i;
338
339 return 0;
340 }
341
342 /*
343 * DCE_STYLE indicates actual RRC is EC + RRC
344 * EC is extra rotate count for DCE_STYLE, pad length otherwise
345 * RRC is rotate count.
346 */
347 static krb5_error_code
kg_translate_iov_v3(krb5_context context,int dce_style,size_t ec,size_t rrc,krb5_enctype enctype,gss_iov_buffer_desc * iov,int iov_count,krb5_crypto_iov ** pkiov,size_t * pkiov_count)348 kg_translate_iov_v3(krb5_context context, int dce_style, size_t ec, size_t rrc,
349 krb5_enctype enctype, gss_iov_buffer_desc *iov,
350 int iov_count, krb5_crypto_iov **pkiov,
351 size_t *pkiov_count)
352 {
353 gss_iov_buffer_t header;
354 gss_iov_buffer_t trailer;
355 int i = 0, j;
356 size_t kiov_count;
357 krb5_crypto_iov *kiov;
358 unsigned int k5_headerlen = 0, k5_trailerlen = 0;
359 size_t gss_headerlen, gss_trailerlen;
360 krb5_error_code code;
361
362 *pkiov = NULL;
363 *pkiov_count = 0;
364
365 header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
366 assert(header != NULL);
367
368 trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
369 assert(trailer == NULL || rrc == 0);
370
371 code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER,
372 &k5_headerlen);
373 if (code != 0)
374 return code;
375
376 code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_TRAILER,
377 &k5_trailerlen);
378 if (code != 0)
379 return code;
380
381 /* Check header and trailer sizes */
382 gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
383 gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
384
385 /* If we're caller without a trailer, we must rotate by trailer length */
386 if (trailer == NULL) {
387 size_t actual_rrc = rrc;
388
389 if (dce_style)
390 actual_rrc += ec; /* compensate for Windows bug */
391
392 if (actual_rrc != gss_trailerlen)
393 return KRB5_BAD_MSIZE;
394
395 gss_headerlen += gss_trailerlen;
396 gss_trailerlen = 0;
397 } else {
398 if (trailer->buffer.length != gss_trailerlen)
399 return KRB5_BAD_MSIZE;
400 }
401
402 if (header->buffer.length != gss_headerlen)
403 return KRB5_BAD_MSIZE;
404
405 kiov_count = 3 + iov_count;
406 kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
407 if (kiov == NULL)
408 return ENOMEM;
409
410 /*
411 * The krb5 header is located at the end of the GSS header.
412 */
413 kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
414 kiov[i].data.length = k5_headerlen;
415 kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
416 i++;
417
418 for (j = 0; j < iov_count; j++) {
419 kiov[i].flags = kg_translate_flag_iov(iov[j].type);
420 if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
421 continue;
422
423 kiov[i].data.length = iov[j].buffer.length;
424 kiov[i].data.data = (char *)iov[j].buffer.value;
425 i++;
426 }
427
428 /*
429 * The EC and encrypted GSS header are placed in the trailer, which may
430 * be rotated directly after the plaintext header if no trailer buffer
431 * is provided.
432 */
433 kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
434 kiov[i].data.length = ec + 16; /* E(Header) */
435 if (trailer == NULL)
436 kiov[i].data.data = (char *)header->buffer.value + 16;
437 else
438 kiov[i].data.data = (char *)trailer->buffer.value;
439 i++;
440
441 /*
442 * The krb5 trailer is placed after the encrypted copy of the
443 * krb5 header (which may be in the GSS header or trailer).
444 */
445 kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
446 kiov[i].data.length = k5_trailerlen;
447 kiov[i].data.data = kiov[i - 1].data.data + ec + 16; /* E(Header) */
448 i++;
449
450 *pkiov = kiov;
451 *pkiov_count = i;
452
453 return 0;
454 }
455
456 /* PROTO is 1 if CFX, 0 if pre-CFX */
457 static krb5_error_code
kg_translate_iov(krb5_context context,int proto,int dce_style,size_t ec,size_t rrc,krb5_enctype enctype,gss_iov_buffer_desc * iov,int iov_count,krb5_crypto_iov ** pkiov,size_t * pkiov_count)458 kg_translate_iov(krb5_context context, int proto, int dce_style, size_t ec,
459 size_t rrc, krb5_enctype enctype, gss_iov_buffer_desc *iov,
460 int iov_count, krb5_crypto_iov **pkiov, size_t *pkiov_count)
461 {
462 return proto ?
463 kg_translate_iov_v3(context, dce_style, ec, rrc, enctype,
464 iov, iov_count, pkiov, pkiov_count) :
465 kg_translate_iov_v1(context, enctype, iov, iov_count,
466 pkiov, pkiov_count);
467 }
468
469 krb5_error_code
kg_encrypt_iov(krb5_context context,int proto,int dce_style,size_t ec,size_t rrc,krb5_key key,int usage,krb5_pointer iv,gss_iov_buffer_desc * iov,int iov_count)470 kg_encrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
471 size_t rrc, krb5_key key, int usage, krb5_pointer iv,
472 gss_iov_buffer_desc *iov, int iov_count)
473 {
474 krb5_error_code code;
475 krb5_data *state;
476 size_t kiov_len;
477 krb5_crypto_iov *kiov;
478
479 code = iv_to_state(context, key, iv, &state);
480 if (code)
481 return code;
482
483 code = kg_translate_iov(context, proto, dce_style, ec, rrc,
484 key->keyblock.enctype, iov, iov_count,
485 &kiov, &kiov_len);
486 if (code == 0) {
487 code = krb5_k_encrypt_iov(context, key, usage, state, kiov, kiov_len);
488 free(kiov);
489 }
490
491 krb5_free_data(context, state);
492 return code;
493 }
494
495 /* length is the length of the cleartext. */
496
497 krb5_error_code
kg_decrypt_iov(krb5_context context,int proto,int dce_style,size_t ec,size_t rrc,krb5_key key,int usage,krb5_pointer iv,gss_iov_buffer_desc * iov,int iov_count)498 kg_decrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
499 size_t rrc, krb5_key key, int usage, krb5_pointer iv,
500 gss_iov_buffer_desc *iov, int iov_count)
501 {
502 krb5_error_code code;
503 krb5_data *state;
504 size_t kiov_len;
505 krb5_crypto_iov *kiov;
506
507 code = iv_to_state(context, key, iv, &state);
508 if (code)
509 return code;
510
511 code = kg_translate_iov(context, proto, dce_style, ec, rrc,
512 key->keyblock.enctype, iov, iov_count,
513 &kiov, &kiov_len);
514 if (code == 0) {
515 code = krb5_k_decrypt_iov(context, key, usage, state, kiov, kiov_len);
516 free(kiov);
517 }
518
519 krb5_free_data(context, state);
520 return code;
521 }
522
523 krb5_error_code
kg_arcfour_docrypt_iov(krb5_context context,const krb5_keyblock * keyblock,int usage,const unsigned char * kd_data,size_t kd_data_len,gss_iov_buffer_desc * iov,int iov_count)524 kg_arcfour_docrypt_iov(krb5_context context, const krb5_keyblock *keyblock,
525 int usage, const unsigned char *kd_data,
526 size_t kd_data_len, gss_iov_buffer_desc *iov,
527 int iov_count)
528 {
529 krb5_error_code code;
530 krb5_data kd = make_data((char *) kd_data, kd_data_len);
531 krb5_crypto_iov *kiov = NULL;
532 size_t kiov_len = 0;
533
534 code = kg_translate_iov(context, 0 /* proto */, 0 /* dce_style */,
535 0 /* ec */, 0 /* rrc */, keyblock->enctype,
536 iov, iov_count, &kiov, &kiov_len);
537 if (code)
538 return code;
539 code = krb5int_arcfour_gsscrypt(keyblock, usage, &kd, kiov, kiov_len);
540 free(kiov);
541 return code;
542 }
543
544 krb5_cryptotype
kg_translate_flag_iov(OM_uint32 type)545 kg_translate_flag_iov(OM_uint32 type)
546 {
547 krb5_cryptotype ktype;
548
549 switch (GSS_IOV_BUFFER_TYPE(type)) {
550 case GSS_IOV_BUFFER_TYPE_DATA:
551 case GSS_IOV_BUFFER_TYPE_PADDING:
552 ktype = KRB5_CRYPTO_TYPE_DATA;
553 break;
554 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
555 ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
556 break;
557 default:
558 ktype = KRB5_CRYPTO_TYPE_EMPTY;
559 break;
560 }
561
562 return ktype;
563 }
564
565 gss_iov_buffer_t
kg_locate_iov(gss_iov_buffer_desc * iov,int iov_count,OM_uint32 type)566 kg_locate_iov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
567 {
568 int i;
569 gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
570
571 if (iov == GSS_C_NO_IOV_BUFFER)
572 return GSS_C_NO_IOV_BUFFER;
573
574 for (i = iov_count - 1; i >= 0; i--) {
575 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
576 if (p == GSS_C_NO_IOV_BUFFER)
577 p = &iov[i];
578 else
579 return GSS_C_NO_IOV_BUFFER;
580 }
581 }
582
583 return p;
584 }
585
586 /* Return the IOV where the GSSAPI token header should be placed (and possibly
587 * the checksum as well, depending on the token type). */
588 gss_iov_buffer_t
kg_locate_header_iov(gss_iov_buffer_desc * iov,int iov_count,int toktype)589 kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count, int toktype)
590 {
591 if (toktype == KG_TOK_MIC_MSG)
592 return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_MIC_TOKEN);
593 else
594 return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
595 }
596
597 void
kg_iov_msglen(gss_iov_buffer_desc * iov,int iov_count,size_t * data_length_p,size_t * assoc_data_length_p)598 kg_iov_msglen(gss_iov_buffer_desc *iov, int iov_count, size_t *data_length_p,
599 size_t *assoc_data_length_p)
600 {
601 int i;
602 size_t data_length = 0, assoc_data_length = 0;
603
604 assert(iov != GSS_C_NO_IOV_BUFFER);
605
606 *data_length_p = *assoc_data_length_p = 0;
607
608 for (i = 0; i < iov_count; i++) {
609 OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
610
611 if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
612 assoc_data_length += iov[i].buffer.length;
613
614 if (type == GSS_IOV_BUFFER_TYPE_DATA ||
615 type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
616 data_length += iov[i].buffer.length;
617 }
618
619 *data_length_p = data_length;
620 *assoc_data_length_p = assoc_data_length;
621 }
622
623 void
kg_release_iov(gss_iov_buffer_desc * iov,int iov_count)624 kg_release_iov(gss_iov_buffer_desc *iov, int iov_count)
625 {
626 int i;
627
628 assert(iov != GSS_C_NO_IOV_BUFFER);
629
630 for (i = 0; i < iov_count; i++) {
631 if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
632 gssalloc_free(iov[i].buffer.value);
633 iov[i].buffer.length = 0;
634 iov[i].buffer.value = NULL;
635 iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
636 }
637 }
638 }
639
640 OM_uint32
kg_fixup_padding_iov(OM_uint32 * minor_status,gss_iov_buffer_desc * iov,int iov_count)641 kg_fixup_padding_iov(OM_uint32 *minor_status, gss_iov_buffer_desc *iov,
642 int iov_count)
643 {
644 gss_iov_buffer_t padding = NULL;
645 gss_iov_buffer_t data = NULL;
646 size_t padlength, relative_padlength;
647 unsigned char *p;
648
649 data = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_DATA);
650 padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
651
652 /* Do nothing if padding is absent or empty, to allow unwrapping of WinRM
653 * unpadded RC4 tokens using an explicit IOV array. */
654 if (data == NULL || padding == NULL || padding->buffer.length == 0) {
655 *minor_status = 0;
656 return GSS_S_COMPLETE;
657 }
658
659 p = (unsigned char *)padding->buffer.value;
660 padlength = p[padding->buffer.length - 1];
661
662 if (data->buffer.length + padding->buffer.length < padlength ||
663 padlength == 0) {
664 *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
665 return GSS_S_DEFECTIVE_TOKEN;
666 }
667
668 /*
669 * kg_unseal_stream_iov() will place one byte of padding in the
670 * padding buffer; its true value is unknown until after decryption.
671 *
672 * relative_padlength contains the number of bytes to compensate the
673 * padding and data buffers by; it will be zero if the caller manages
674 * the padding length.
675 *
676 * If the caller manages the padding length, then relative_padlength
677 * will be zero.
678 *
679 * eg. if the buffers are structured as follows:
680 *
681 * +---DATA---+-PAD-+
682 * | ABCDE444 | 4 |
683 * +----------+-----+
684 *
685 * after compensation they would look like:
686 *
687 * +-DATA--+-PAD--+
688 * | ABCDE | NULL |
689 * +-------+------+
690 */
691 relative_padlength = padlength - padding->buffer.length;
692
693 assert(data->buffer.length >= relative_padlength);
694
695 data->buffer.length -= relative_padlength;
696
697 kg_release_iov(padding, 1);
698 padding->buffer.length = 0;
699 padding->buffer.value = NULL;
700
701 return GSS_S_COMPLETE;
702 }
703
704 krb5_boolean
kg_integ_only_iov(gss_iov_buffer_desc * iov,int iov_count)705 kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count)
706 {
707 int i;
708 krb5_boolean has_conf_data = FALSE;
709
710 assert(iov != GSS_C_NO_IOV_BUFFER);
711
712 for (i = 0; i < iov_count; i++) {
713 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
714 has_conf_data = TRUE;
715 break;
716 }
717 }
718
719 return (has_conf_data == FALSE);
720 }
721
722 krb5_error_code
kg_allocate_iov(gss_iov_buffer_t iov,size_t size)723 kg_allocate_iov(gss_iov_buffer_t iov, size_t size)
724 {
725 assert(iov != GSS_C_NO_IOV_BUFFER);
726 assert(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
727
728 iov->buffer.length = size;
729 iov->buffer.value = gssalloc_malloc(size);
730 if (iov->buffer.value == NULL) {
731 iov->buffer.length = 0;
732 return ENOMEM;
733 }
734
735 iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
736
737 return 0;
738 }
739