xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/util_crypt.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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