Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / src / lib / gssapi / krb5 / util_crypt.c
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
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 static krb5_error_code
78 kg_derive_des_enc_key(krb5_context context, krb5_key subkey, krb5_key *out)
79 {
80     krb5_error_code code;
81     krb5_keyblock *keyblock;
82     unsigned int i;
83
84     *out = NULL;
85
86     code = krb5_k_key_keyblock(context, subkey, &keyblock);
87     if (code != 0)
88         return code;
89
90     for (i = 0; i < keyblock->length; i++)
91         keyblock->contents[i] ^= 0xF0;
92
93     code = krb5_k_create_key(context, keyblock, out);
94     krb5_free_keyblock(context, keyblock);
95     return code;
96 }
97
98 krb5_error_code
99 kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
100               krb5_cksumtype *cksumtype)
101 {
102     krb5_error_code code;
103
104     assert(ctx != NULL);
105     assert(subkey != NULL);
106
107     *cksumtype = 0;
108     ctx->proto = 0;
109
110     if (ctx->enc == NULL) {
111         ctx->signalg = -1;
112         ctx->sealalg = -1;
113     }
114
115     code = krb5int_c_mandatory_cksumtype(context, subkey->keyblock.enctype,
116                                          cksumtype);
117     if (code != 0)
118         return code;
119
120     switch (subkey->keyblock.enctype) {
121     case ENCTYPE_DES_CBC_MD5:
122     case ENCTYPE_DES_CBC_MD4:
123     case ENCTYPE_DES_CBC_CRC:
124         krb5_k_free_key(context, ctx->seq);
125         code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
126         if (code != 0)
127             return code;
128
129         krb5_k_free_key(context, ctx->enc);
130         code = kg_derive_des_enc_key(context, subkey, &ctx->enc);
131         if (code != 0)
132             return code;
133
134         ctx->enc->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
135         ctx->seq->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
136         ctx->signalg = SGN_ALG_DES_MAC_MD5;
137         ctx->cksum_size = 8;
138         ctx->sealalg = SEAL_ALG_DES;
139
140         break;
141     case ENCTYPE_DES3_CBC_SHA1:
142         code = kg_copy_keys(context, ctx, subkey);
143         if (code != 0)
144             return code;
145
146         ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
147         ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
148         ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
149         ctx->cksum_size = 20;
150         ctx->sealalg = SEAL_ALG_DES3KD;
151         break;
152     case ENCTYPE_ARCFOUR_HMAC:
153     case ENCTYPE_ARCFOUR_HMAC_EXP:
154         /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer" enctype,
155          * even though RFC 4757 treats it as one. */
156         code = kg_copy_keys(context, ctx, subkey);
157         if (code != 0)
158             return code;
159
160         ctx->signalg = SGN_ALG_HMAC_MD5;
161         ctx->cksum_size = 8;
162         ctx->sealalg = SEAL_ALG_MICROSOFT_RC4;
163         break;
164     default:
165         ctx->proto = 1;
166         break;
167     }
168
169     return 0;
170 }
171
172 int
173 kg_confounder_size(krb5_context context, krb5_enctype enctype)
174 {
175     krb5_error_code code;
176     size_t blocksize;
177     /* We special case rc4*/
178     if (enctype == ENCTYPE_ARCFOUR_HMAC || enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
179         return 8;
180     code = krb5_c_block_size(context, enctype, &blocksize);
181     if (code)
182         return(-1); /* XXX */
183
184     return(blocksize);
185 }
186
187 krb5_error_code
188 kg_make_confounder(krb5_context context, krb5_enctype enctype,
189                    unsigned char *buf)
190 {
191     int confsize;
192     krb5_data lrandom;
193
194     confsize = kg_confounder_size(context, enctype);
195     if (confsize < 0)
196         return KRB5_BAD_MSIZE;
197
198     lrandom.length = confsize;
199     lrandom.data = (char *)buf;
200
201     return(krb5_c_random_make_octets(context, &lrandom));
202 }
203
204 /* Set *data_out to a krb5_data structure containing iv, or to NULL if iv is
205  * NULL. */
206 static krb5_error_code
207 iv_to_state(krb5_context context, krb5_key key, krb5_pointer iv,
208             krb5_data **data_out)
209 {
210     krb5_error_code code;
211     krb5_data *data;
212     size_t blocksize;
213
214     *data_out = NULL;
215     if (iv == NULL)
216         return 0;
217
218     code = krb5_c_block_size(context, key->keyblock.enctype, &blocksize);
219     if (code)
220         return code;
221
222     data = k5alloc(sizeof(*data), &code);
223     if (data == NULL)
224         return code;
225     code = alloc_data(data, blocksize);
226     if (code) {
227         free(data);
228         return code;
229     }
230     memcpy(data->data, iv, blocksize);
231     *data_out = data;
232     return 0;
233 }
234
235 krb5_error_code
236 kg_encrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
237            krb5_const_pointer in, krb5_pointer out, unsigned int length)
238 {
239     krb5_error_code code;
240     krb5_data *state, inputd;
241     krb5_enc_data outputd;
242
243     code = iv_to_state(context, key, iv, &state);
244     if (code)
245         return code;
246
247     inputd.length = length;
248     inputd.data = (char *)in;
249
250     outputd.ciphertext.length = length;
251     outputd.ciphertext.data = out;
252
253     code = krb5_k_encrypt(context, key, usage, state, &inputd, &outputd);
254     krb5_free_data(context, state);
255     return code;
256 }
257
258 krb5_error_code
259 kg_encrypt_inplace(krb5_context context, krb5_key key, int usage,
260                    krb5_pointer iv, krb5_pointer ptr, unsigned int length)
261 {
262     krb5_error_code code;
263     krb5_crypto_iov iov;
264     krb5_data *state;
265
266     code = iv_to_state(context, key, iv, &state);
267     if (code)
268         return code;
269
270     iov.flags = KRB5_CRYPTO_TYPE_DATA;
271     iov.data = make_data((void *)ptr, length);
272     code = krb5_k_encrypt_iov(context, key, usage, state, &iov, 1);
273     krb5_free_data(context, state);
274     return code;
275 }
276
277 /* length is the length of the cleartext. */
278
279 krb5_error_code
280 kg_decrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
281            krb5_const_pointer in, krb5_pointer out, unsigned int length)
282 {
283     krb5_error_code code;
284     krb5_data *state, outputd;
285     krb5_enc_data inputd;
286
287     code = iv_to_state(context, key, iv, &state);
288     if (code)
289         return code;
290
291     inputd.enctype = ENCTYPE_UNKNOWN;
292     inputd.ciphertext.length = length;
293     inputd.ciphertext.data = (char *)in;
294
295     outputd.length = length;
296     outputd.data = out;
297
298     code = krb5_k_decrypt(context, key, usage, state, &inputd, &outputd);
299     krb5_free_data(context, state);
300     return code;
301 }
302
303 krb5_error_code
304 kg_arcfour_docrypt(const krb5_keyblock *keyblock, int usage,
305                    const unsigned char *kd_data, size_t kd_data_len,
306                    const unsigned char *input_buf, size_t input_len,
307                    unsigned char *output_buf)
308 {
309     krb5_data kd = make_data((char *) kd_data, kd_data_len);
310     krb5_crypto_iov kiov;
311
312     memcpy(output_buf, input_buf, input_len);
313     kiov.flags = KRB5_CRYPTO_TYPE_DATA;
314     kiov.data = make_data(output_buf, input_len);
315     return krb5int_arcfour_gsscrypt(keyblock, usage, &kd, &kiov, 1);
316 }
317
318 /* AEAD */
319 static krb5_error_code
320 kg_translate_iov_v1(krb5_context context, krb5_enctype enctype,
321                     gss_iov_buffer_desc *iov, int iov_count,
322                     krb5_crypto_iov **pkiov, size_t *pkiov_count)
323 {
324     gss_iov_buffer_desc *header;
325     gss_iov_buffer_desc *trailer;
326     int i = 0, j;
327     size_t kiov_count;
328     krb5_crypto_iov *kiov;
329     size_t conf_len;
330
331     *pkiov = NULL;
332     *pkiov_count = 0;
333
334     conf_len = kg_confounder_size(context, enctype);
335
336     header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
337     assert(header != NULL);
338
339     if (header->buffer.length < conf_len)
340         return KRB5_BAD_MSIZE;
341
342     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
343     assert(trailer == NULL || trailer->buffer.length == 0);
344
345     kiov_count = 3 + iov_count;
346     kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
347     if (kiov == NULL)
348         return ENOMEM;
349
350     /* For pre-CFX (raw enctypes) there is no krb5 header */
351     kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
352     kiov[i].data.length = 0;
353     kiov[i].data.data = NULL;
354     i++;
355
356     /* For pre-CFX, the confounder is at the end of the GSS header */
357     kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
358     kiov[i].data.length = conf_len;
359     kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
360     i++;
361
362     for (j = 0; j < iov_count; j++) {
363         kiov[i].flags = kg_translate_flag_iov(iov[j].type);
364         if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
365             continue;
366
367         kiov[i].data.length = iov[j].buffer.length;
368         kiov[i].data.data = (char *)iov[j].buffer.value;
369         i++;
370     }
371
372     kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
373     kiov[i].data.length = 0;
374     kiov[i].data.data = NULL;
375     i++;
376
377     *pkiov = kiov;
378     *pkiov_count = i;
379
380     return 0;
381 }
382
383 /*
384  * DCE_STYLE indicates actual RRC is EC + RRC
385  * EC is extra rotate count for DCE_STYLE, pad length otherwise
386  * RRC is rotate count.
387  */
388 static krb5_error_code
389 kg_translate_iov_v3(krb5_context context, int dce_style, size_t ec, size_t rrc,
390                     krb5_enctype enctype, gss_iov_buffer_desc *iov,
391                     int iov_count, krb5_crypto_iov **pkiov,
392                     size_t *pkiov_count)
393 {
394     gss_iov_buffer_t header;
395     gss_iov_buffer_t trailer;
396     int i = 0, j;
397     size_t kiov_count;
398     krb5_crypto_iov *kiov;
399     unsigned int k5_headerlen = 0, k5_trailerlen = 0;
400     size_t gss_headerlen, gss_trailerlen;
401     krb5_error_code code;
402
403     *pkiov = NULL;
404     *pkiov_count = 0;
405
406     header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
407     assert(header != NULL);
408
409     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
410     assert(trailer == NULL || rrc == 0);
411
412     code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER,
413                                 &k5_headerlen);
414     if (code != 0)
415         return code;
416
417     code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_TRAILER,
418                                 &k5_trailerlen);
419     if (code != 0)
420         return code;
421
422     /* Check header and trailer sizes */
423     gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
424     gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
425
426     /* If we're caller without a trailer, we must rotate by trailer length */
427     if (trailer == NULL) {
428         size_t actual_rrc = rrc;
429
430         if (dce_style)
431             actual_rrc += ec; /* compensate for Windows bug */
432
433         if (actual_rrc != gss_trailerlen)
434             return KRB5_BAD_MSIZE;
435
436         gss_headerlen += gss_trailerlen;
437         gss_trailerlen = 0;
438     } else {
439         if (trailer->buffer.length != gss_trailerlen)
440             return KRB5_BAD_MSIZE;
441     }
442
443     if (header->buffer.length != gss_headerlen)
444         return KRB5_BAD_MSIZE;
445
446     kiov_count = 3 + iov_count;
447     kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
448     if (kiov == NULL)
449         return ENOMEM;
450
451     /*
452      * The krb5 header is located at the end of the GSS header.
453      */
454     kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
455     kiov[i].data.length = k5_headerlen;
456     kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
457     i++;
458
459     for (j = 0; j < iov_count; j++) {
460         kiov[i].flags = kg_translate_flag_iov(iov[j].type);
461         if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
462             continue;
463
464         kiov[i].data.length = iov[j].buffer.length;
465         kiov[i].data.data = (char *)iov[j].buffer.value;
466         i++;
467     }
468
469     /*
470      * The EC and encrypted GSS header are placed in the trailer, which may
471      * be rotated directly after the plaintext header if no trailer buffer
472      * is provided.
473      */
474     kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
475     kiov[i].data.length = ec + 16; /* E(Header) */
476     if (trailer == NULL)
477         kiov[i].data.data = (char *)header->buffer.value + 16;
478     else
479         kiov[i].data.data = (char *)trailer->buffer.value;
480     i++;
481
482     /*
483      * The krb5 trailer is placed after the encrypted copy of the
484      * krb5 header (which may be in the GSS header or trailer).
485      */
486     kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
487     kiov[i].data.length = k5_trailerlen;
488     kiov[i].data.data = kiov[i - 1].data.data + ec + 16; /* E(Header) */
489     i++;
490
491     *pkiov = kiov;
492     *pkiov_count = i;
493
494     return 0;
495 }
496
497 /* PROTO is 1 if CFX, 0 if pre-CFX */
498 static krb5_error_code
499 kg_translate_iov(krb5_context context, int proto, int dce_style, size_t ec,
500                  size_t rrc, krb5_enctype enctype, gss_iov_buffer_desc *iov,
501                  int iov_count, krb5_crypto_iov **pkiov, size_t *pkiov_count)
502 {
503     return proto ?
504         kg_translate_iov_v3(context, dce_style, ec, rrc, enctype,
505                             iov, iov_count, pkiov, pkiov_count) :
506         kg_translate_iov_v1(context, enctype, iov, iov_count,
507                             pkiov, pkiov_count);
508 }
509
510 krb5_error_code
511 kg_encrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
512                size_t rrc, krb5_key key, int usage, krb5_pointer iv,
513                gss_iov_buffer_desc *iov, int iov_count)
514 {
515     krb5_error_code code;
516     krb5_data *state;
517     size_t kiov_len;
518     krb5_crypto_iov *kiov;
519
520     code = iv_to_state(context, key, iv, &state);
521     if (code)
522         return code;
523
524     code = kg_translate_iov(context, proto, dce_style, ec, rrc,
525                             key->keyblock.enctype, iov, iov_count,
526                             &kiov, &kiov_len);
527     if (code == 0) {
528         code = krb5_k_encrypt_iov(context, key, usage, state, kiov, kiov_len);
529         free(kiov);
530     }
531
532     krb5_free_data(context, state);
533     return code;
534 }
535
536 /* length is the length of the cleartext. */
537
538 krb5_error_code
539 kg_decrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
540                size_t rrc, krb5_key key, int usage, krb5_pointer iv,
541                gss_iov_buffer_desc *iov, int iov_count)
542 {
543     krb5_error_code code;
544     krb5_data *state;
545     size_t kiov_len;
546     krb5_crypto_iov *kiov;
547
548     code = iv_to_state(context, key, iv, &state);
549     if (code)
550         return code;
551
552     code = kg_translate_iov(context, proto, dce_style, ec, rrc,
553                             key->keyblock.enctype, iov, iov_count,
554                             &kiov, &kiov_len);
555     if (code == 0) {
556         code = krb5_k_decrypt_iov(context, key, usage, state, kiov, kiov_len);
557         free(kiov);
558     }
559
560     krb5_free_data(context, state);
561     return code;
562 }
563
564 krb5_error_code
565 kg_arcfour_docrypt_iov(krb5_context context, const krb5_keyblock *keyblock,
566                        int usage, const unsigned char *kd_data,
567                        size_t kd_data_len, gss_iov_buffer_desc *iov,
568                        int iov_count)
569 {
570     krb5_error_code code;
571     krb5_data kd = make_data((char *) kd_data, kd_data_len);
572     krb5_crypto_iov *kiov = NULL;
573     size_t kiov_len = 0;
574
575     code = kg_translate_iov(context, 0 /* proto */, 0 /* dce_style */,
576                             0 /* ec */, 0 /* rrc */, keyblock->enctype,
577                             iov, iov_count, &kiov, &kiov_len);
578     if (code)
579         return code;
580     code = krb5int_arcfour_gsscrypt(keyblock, usage, &kd, kiov, kiov_len);
581     free(kiov);
582     return code;
583 }
584
585 krb5_cryptotype
586 kg_translate_flag_iov(OM_uint32 type)
587 {
588     krb5_cryptotype ktype;
589
590     switch (GSS_IOV_BUFFER_TYPE(type)) {
591     case GSS_IOV_BUFFER_TYPE_DATA:
592     case GSS_IOV_BUFFER_TYPE_PADDING:
593         ktype = KRB5_CRYPTO_TYPE_DATA;
594         break;
595     case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
596         ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
597         break;
598     default:
599         ktype = KRB5_CRYPTO_TYPE_EMPTY;
600         break;
601     }
602
603     return ktype;
604 }
605
606 gss_iov_buffer_t
607 kg_locate_iov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
608 {
609     int i;
610     gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
611
612     if (iov == GSS_C_NO_IOV_BUFFER)
613         return GSS_C_NO_IOV_BUFFER;
614
615     for (i = iov_count - 1; i >= 0; i--) {
616         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
617             if (p == GSS_C_NO_IOV_BUFFER)
618                 p = &iov[i];
619             else
620                 return GSS_C_NO_IOV_BUFFER;
621         }
622     }
623
624     return p;
625 }
626
627 /* Return the IOV where the GSSAPI token header should be placed (and possibly
628  * the checksum as well, depending on the token type). */
629 gss_iov_buffer_t
630 kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count, int toktype)
631 {
632     if (toktype == KG_TOK_MIC_MSG)
633         return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_MIC_TOKEN);
634     else
635         return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
636 }
637
638 void
639 kg_iov_msglen(gss_iov_buffer_desc *iov, int iov_count, size_t *data_length_p,
640               size_t *assoc_data_length_p)
641 {
642     int i;
643     size_t data_length = 0, assoc_data_length = 0;
644
645     assert(iov != GSS_C_NO_IOV_BUFFER);
646
647     *data_length_p = *assoc_data_length_p = 0;
648
649     for (i = 0; i < iov_count; i++) {
650         OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
651
652         if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
653             assoc_data_length += iov[i].buffer.length;
654
655         if (type == GSS_IOV_BUFFER_TYPE_DATA ||
656             type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
657             data_length += iov[i].buffer.length;
658     }
659
660     *data_length_p = data_length;
661     *assoc_data_length_p = assoc_data_length;
662 }
663
664 void
665 kg_release_iov(gss_iov_buffer_desc *iov, int iov_count)
666 {
667     int i;
668
669     assert(iov != GSS_C_NO_IOV_BUFFER);
670
671     for (i = 0; i < iov_count; i++) {
672         if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
673             gssalloc_free(iov[i].buffer.value);
674             iov[i].buffer.length = 0;
675             iov[i].buffer.value = NULL;
676             iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
677         }
678     }
679 }
680
681 OM_uint32
682 kg_fixup_padding_iov(OM_uint32 *minor_status, gss_iov_buffer_desc *iov,
683                      int iov_count)
684 {
685     gss_iov_buffer_t padding = NULL;
686     gss_iov_buffer_t data = NULL;
687     size_t padlength, relative_padlength;
688     unsigned char *p;
689
690     data = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_DATA);
691     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
692
693     if (data == NULL) {
694         *minor_status = 0;
695         return GSS_S_COMPLETE;
696     }
697
698     if (padding == NULL || padding->buffer.length == 0) {
699         *minor_status = EINVAL;
700         return GSS_S_FAILURE;
701     }
702
703     p = (unsigned char *)padding->buffer.value;
704     padlength = p[padding->buffer.length - 1];
705
706     if (data->buffer.length + padding->buffer.length < padlength ||
707         padlength == 0) {
708         *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
709         return GSS_S_DEFECTIVE_TOKEN;
710     }
711
712     /*
713      * kg_unseal_stream_iov() will place one byte of padding in the
714      * padding buffer; its true value is unknown until after decryption.
715      *
716      * relative_padlength contains the number of bytes to compensate the
717      * padding and data buffers by; it will be zero if the caller manages
718      * the padding length.
719      *
720      * If the caller manages the padding length, then relative_padlength
721      * wil be zero.
722      *
723      * eg. if the buffers are structured as follows:
724      *
725      *      +---DATA---+-PAD-+
726      *      | ABCDE444 | 4   |
727      *      +----------+-----+
728      *
729      * after compensation they would look like:
730      *
731      *      +-DATA--+-PAD--+
732      *      | ABCDE | NULL |
733      *      +-------+------+
734      */
735     relative_padlength = padlength - padding->buffer.length;
736
737     assert(data->buffer.length >= relative_padlength);
738
739     data->buffer.length -= relative_padlength;
740
741     kg_release_iov(padding, 1);
742     padding->buffer.length = 0;
743     padding->buffer.value = NULL;
744
745     return GSS_S_COMPLETE;
746 }
747
748 krb5_boolean
749 kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count)
750 {
751     int i;
752     krb5_boolean has_conf_data = FALSE;
753
754     assert(iov != GSS_C_NO_IOV_BUFFER);
755
756     for (i = 0; i < iov_count; i++) {
757         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
758             has_conf_data = TRUE;
759             break;
760         }
761     }
762
763     return (has_conf_data == FALSE);
764 }
765
766 krb5_error_code
767 kg_allocate_iov(gss_iov_buffer_t iov, size_t size)
768 {
769     assert(iov != GSS_C_NO_IOV_BUFFER);
770     assert(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
771
772     iov->buffer.length = size;
773     iov->buffer.value = gssalloc_malloc(size);
774     if (iov->buffer.value == NULL) {
775         iov->buffer.length = 0;
776         return ENOMEM;
777     }
778
779     iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
780
781     return 0;
782 }