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