]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/kgssapi/krb5/krb5_mech.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / kgssapi / krb5 / krb5_mech.c
1 /*-
2  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3  * Authors: Doug Rabson <dfr@rabson.org>
4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_inet6.h"
32
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/kobj.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
41 #include <kgssapi/gssapi.h>
42 #include <kgssapi/gssapi_impl.h>
43
44 #include "kgss_if.h"
45 #include "kcrypto.h"
46
47 #define GSS_TOKEN_SENT_BY_ACCEPTOR      1
48 #define GSS_TOKEN_SEALED                2
49 #define GSS_TOKEN_ACCEPTOR_SUBKEY       4
50
51 static gss_OID_desc krb5_mech_oid =
52 {9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
53
54 struct krb5_data {
55         size_t          kd_length;
56         void            *kd_data;
57 };
58
59 struct krb5_keyblock {
60         uint16_t        kk_type; /* encryption type */
61         struct krb5_data kk_key; /* key data */
62 };
63
64 struct krb5_address {
65         uint16_t        ka_type;
66         struct krb5_data ka_addr;
67 };
68
69 /*
70  * The km_elem array is ordered so that the highest received sequence
71  * number is listed first.
72  */
73 struct krb5_msg_order {
74         uint32_t                km_flags;
75         uint32_t                km_start;
76         uint32_t                km_length;
77         uint32_t                km_jitter_window;
78         uint32_t                km_first_seq;
79         uint32_t                *km_elem;
80 };
81
82 struct krb5_context {
83         struct _gss_ctx_id_t    kc_common;
84         struct mtx              kc_lock;
85         uint32_t                kc_ac_flags;
86         uint32_t                kc_ctx_flags;
87         uint32_t                kc_more_flags;
88 #define LOCAL                   1
89 #define OPEN                    2
90 #define COMPAT_OLD_DES3         4
91 #define COMPAT_OLD_DES3_SELECTED 8
92 #define ACCEPTOR_SUBKEY         16
93         struct krb5_address     kc_local_address;
94         struct krb5_address     kc_remote_address;
95         uint16_t                kc_local_port;
96         uint16_t                kc_remote_port;
97         struct krb5_keyblock    kc_keyblock;
98         struct krb5_keyblock    kc_local_subkey;
99         struct krb5_keyblock    kc_remote_subkey;
100         volatile uint32_t       kc_local_seqnumber;
101         uint32_t                kc_remote_seqnumber;
102         uint32_t                kc_keytype;
103         uint32_t                kc_cksumtype;
104         struct krb5_data        kc_source_name;
105         struct krb5_data        kc_target_name;
106         uint32_t                kc_lifetime;
107         struct krb5_msg_order   kc_msg_order;
108         struct krb5_key_state   *kc_tokenkey;
109         struct krb5_key_state   *kc_encryptkey;
110         struct krb5_key_state   *kc_checksumkey;
111
112         struct krb5_key_state   *kc_send_seal_Ke;
113         struct krb5_key_state   *kc_send_seal_Ki;
114         struct krb5_key_state   *kc_send_seal_Kc;
115         struct krb5_key_state   *kc_send_sign_Kc;
116
117         struct krb5_key_state   *kc_recv_seal_Ke;
118         struct krb5_key_state   *kc_recv_seal_Ki;
119         struct krb5_key_state   *kc_recv_seal_Kc;
120         struct krb5_key_state   *kc_recv_sign_Kc;
121 };
122
123 static uint16_t
124 get_uint16(const uint8_t **pp, size_t *lenp)
125 {
126         const uint8_t *p = *pp;
127         uint16_t v;
128
129         if (*lenp < 2)
130                 return (0);
131
132         v = (p[0] << 8) | p[1];
133         *pp = p + 2;
134         *lenp = *lenp - 2;
135
136         return (v);
137 }
138
139 static uint32_t
140 get_uint32(const uint8_t **pp, size_t *lenp)
141 {
142         const uint8_t *p = *pp;
143         uint32_t v;
144
145         if (*lenp < 4)
146                 return (0);
147
148         v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
149         *pp = p + 4;
150         *lenp = *lenp - 4;
151
152         return (v);
153 }
154
155 static void
156 get_data(const uint8_t **pp, size_t *lenp, struct krb5_data *dp)
157 {
158         size_t sz = get_uint32(pp, lenp);
159
160         dp->kd_length = sz;
161         dp->kd_data = malloc(sz, M_GSSAPI, M_WAITOK);
162
163         if (*lenp < sz)
164                 sz = *lenp;
165         bcopy(*pp, dp->kd_data, sz);
166         (*pp) += sz;
167         (*lenp) -= sz;
168 }
169
170 static void
171 delete_data(struct krb5_data *dp)
172 {
173         if (dp->kd_data) {
174                 free(dp->kd_data, M_GSSAPI);
175                 dp->kd_length = 0;
176                 dp->kd_data = NULL;
177         }
178 }
179
180 static void
181 get_address(const uint8_t **pp, size_t *lenp, struct krb5_address *ka)
182 {
183
184         ka->ka_type = get_uint16(pp, lenp);
185         get_data(pp, lenp, &ka->ka_addr);
186 }
187
188 static void
189 delete_address(struct krb5_address *ka)
190 {
191         delete_data(&ka->ka_addr);
192 }
193
194 static void
195 get_keyblock(const uint8_t **pp, size_t *lenp, struct krb5_keyblock *kk)
196 {
197
198         kk->kk_type = get_uint16(pp, lenp);
199         get_data(pp, lenp, &kk->kk_key);
200 }
201
202 static void
203 delete_keyblock(struct krb5_keyblock *kk)
204 {
205         if (kk->kk_key.kd_data)
206                 bzero(kk->kk_key.kd_data, kk->kk_key.kd_length);
207         delete_data(&kk->kk_key);
208 }
209
210 static void
211 copy_key(struct krb5_keyblock *from, struct krb5_keyblock **to)
212 {
213
214         if (from->kk_key.kd_length)
215                 *to = from;
216         else
217                 *to = NULL;
218 }
219
220 /*
221  * Return non-zero if we are initiator.
222  */
223 static __inline int
224 is_initiator(struct krb5_context *kc)
225 {
226         return (kc->kc_more_flags & LOCAL);
227 }
228
229 /*
230  * Return non-zero if we are acceptor.
231  */
232 static __inline int
233 is_acceptor(struct krb5_context *kc)
234 {
235         return !(kc->kc_more_flags & LOCAL);
236 }
237
238 static void
239 get_initiator_subkey(struct krb5_context *kc, struct krb5_keyblock **kdp)
240 {
241
242         if (is_initiator(kc))
243                 copy_key(&kc->kc_local_subkey, kdp);
244         else
245                 copy_key(&kc->kc_remote_subkey, kdp);
246         if (!*kdp)
247                 copy_key(&kc->kc_keyblock, kdp);
248 }
249
250 static void
251 get_acceptor_subkey(struct krb5_context *kc, struct krb5_keyblock **kdp)
252 {
253
254         if (is_initiator(kc))
255                 copy_key(&kc->kc_remote_subkey, kdp);
256         else
257                 copy_key(&kc->kc_local_subkey, kdp);
258 }
259
260 static OM_uint32
261 get_keys(struct krb5_context *kc)
262 {
263         struct krb5_keyblock *keydata;
264         struct krb5_encryption_class *ec;
265         struct krb5_key_state *key;
266         int etype;
267
268         keydata = NULL;
269         get_acceptor_subkey(kc, &keydata);
270         if (!keydata)
271                 if ((kc->kc_more_flags & ACCEPTOR_SUBKEY) == 0)
272                         get_initiator_subkey(kc, &keydata);
273         if (!keydata)
274                 return (GSS_S_FAILURE);
275
276         /*
277          * GSS-API treats all DES etypes the same and all DES3 etypes
278          * the same.
279          */
280         switch (keydata->kk_type) {
281         case ETYPE_DES_CBC_CRC:
282         case ETYPE_DES_CBC_MD4:
283         case ETYPE_DES_CBC_MD5:
284                 etype = ETYPE_DES_CBC_CRC;
285                 break;
286
287         case ETYPE_DES3_CBC_MD5:
288         case ETYPE_DES3_CBC_SHA1:
289         case ETYPE_OLD_DES3_CBC_SHA1:
290                 etype = ETYPE_DES3_CBC_SHA1;
291                 break;
292
293         default:
294                 etype = keydata->kk_type;
295         }
296
297         ec = krb5_find_encryption_class(etype);
298         if (!ec)
299                 return (GSS_S_FAILURE);
300
301         key = krb5_create_key(ec);
302         krb5_set_key(key, keydata->kk_key.kd_data);
303         kc->kc_tokenkey = key;
304
305         switch (etype) {
306         case ETYPE_DES_CBC_CRC:
307         case ETYPE_ARCFOUR_HMAC_MD5: 
308         case ETYPE_ARCFOUR_HMAC_MD5_56: {
309                 /*
310                  * Single DES and ARCFOUR uses a 'derived' key (XOR
311                  * with 0xf0) for encrypting wrap tokens. The original
312                  * key is used for checksums and sequence numbers.
313                  */
314                 struct krb5_key_state *ekey;
315                 uint8_t *ekp, *kp;
316                 int i;
317
318                 ekey = krb5_create_key(ec);
319                 ekp = ekey->ks_key;
320                 kp = key->ks_key;
321                 for (i = 0; i < ec->ec_keylen; i++)
322                         ekp[i] = kp[i] ^ 0xf0;
323                 krb5_set_key(ekey, ekp);
324                 kc->kc_encryptkey = ekey;
325                 refcount_acquire(&key->ks_refs);
326                 kc->kc_checksumkey = key;
327                 break;
328         }
329
330         case ETYPE_DES3_CBC_SHA1:
331                 /*
332                  * Triple DES uses a RFC 3961 style derived key with
333                  * usage number KG_USAGE_SIGN for checksums. The
334                  * original key is used for encryption and sequence
335                  * numbers.
336                  */
337                 kc->kc_checksumkey = krb5_get_checksum_key(key, KG_USAGE_SIGN);
338                 refcount_acquire(&key->ks_refs);
339                 kc->kc_encryptkey = key;
340                 break;
341
342         default:
343                 /*
344                  * We need eight derived keys four for sending and
345                  * four for receiving.
346                  */
347                 if (is_initiator(kc)) {
348                         /*
349                          * We are initiator.
350                          */
351                         kc->kc_send_seal_Ke = krb5_get_encryption_key(key,
352                             KG_USAGE_INITIATOR_SEAL);
353                         kc->kc_send_seal_Ki = krb5_get_integrity_key(key,
354                             KG_USAGE_INITIATOR_SEAL);
355                         kc->kc_send_seal_Kc = krb5_get_checksum_key(key,
356                             KG_USAGE_INITIATOR_SEAL);
357                         kc->kc_send_sign_Kc = krb5_get_checksum_key(key,
358                             KG_USAGE_INITIATOR_SIGN);
359
360                         kc->kc_recv_seal_Ke = krb5_get_encryption_key(key,
361                             KG_USAGE_ACCEPTOR_SEAL);
362                         kc->kc_recv_seal_Ki = krb5_get_integrity_key(key,
363                             KG_USAGE_ACCEPTOR_SEAL);
364                         kc->kc_recv_seal_Kc = krb5_get_checksum_key(key,
365                             KG_USAGE_ACCEPTOR_SEAL);
366                         kc->kc_recv_sign_Kc = krb5_get_checksum_key(key,
367                             KG_USAGE_ACCEPTOR_SIGN);
368                 } else {
369                         /*
370                          * We are acceptor.
371                          */
372                         kc->kc_send_seal_Ke = krb5_get_encryption_key(key,
373                             KG_USAGE_ACCEPTOR_SEAL);
374                         kc->kc_send_seal_Ki = krb5_get_integrity_key(key,
375                             KG_USAGE_ACCEPTOR_SEAL);
376                         kc->kc_send_seal_Kc = krb5_get_checksum_key(key,
377                             KG_USAGE_ACCEPTOR_SEAL);
378                         kc->kc_send_sign_Kc = krb5_get_checksum_key(key,
379                             KG_USAGE_ACCEPTOR_SIGN);
380
381                         kc->kc_recv_seal_Ke = krb5_get_encryption_key(key,
382                             KG_USAGE_INITIATOR_SEAL);
383                         kc->kc_recv_seal_Ki = krb5_get_integrity_key(key,
384                             KG_USAGE_INITIATOR_SEAL);
385                         kc->kc_recv_seal_Kc = krb5_get_checksum_key(key,
386                             KG_USAGE_INITIATOR_SEAL);
387                         kc->kc_recv_sign_Kc = krb5_get_checksum_key(key,
388                             KG_USAGE_INITIATOR_SIGN);
389                 }
390                 break;
391         }
392
393         return (GSS_S_COMPLETE);
394 }
395
396 static void
397 krb5_init(gss_ctx_id_t ctx)
398 {
399         struct krb5_context *kc = (struct krb5_context *)ctx;
400
401         mtx_init(&kc->kc_lock, "krb5 gss lock", NULL, MTX_DEF);
402 }
403
404 static OM_uint32
405 krb5_import(gss_ctx_id_t ctx,
406     enum sec_context_format format,
407     const gss_buffer_t context_token)
408 {
409         struct krb5_context *kc = (struct krb5_context *)ctx;
410         OM_uint32 res;
411         const uint8_t *p = (const uint8_t *) context_token->value;
412         size_t len = context_token->length;
413         uint32_t flags;
414         int i;
415         
416         /*
417          * We support heimdal 0.6 and heimdal 1.1
418          */
419         if (format != KGSS_HEIMDAL_0_6 && format != KGSS_HEIMDAL_1_1)
420                 return (GSS_S_DEFECTIVE_TOKEN);
421
422 #define SC_LOCAL_ADDRESS        1
423 #define SC_REMOTE_ADDRESS       2
424 #define SC_KEYBLOCK             4
425 #define SC_LOCAL_SUBKEY         8
426 #define SC_REMOTE_SUBKEY        16
427
428         /*
429          * Ensure that the token starts with krb5 oid.
430          */
431         if (p[0] != 0x00 || p[1] != krb5_mech_oid.length
432             || len < krb5_mech_oid.length + 2
433             || bcmp(krb5_mech_oid.elements, p + 2,
434                 krb5_mech_oid.length))
435                 return (GSS_S_DEFECTIVE_TOKEN);
436         p += krb5_mech_oid.length + 2;
437         len -= krb5_mech_oid.length + 2;
438
439         flags = get_uint32(&p, &len);
440         kc->kc_ac_flags = get_uint32(&p, &len);
441         if (flags & SC_LOCAL_ADDRESS)
442                 get_address(&p, &len, &kc->kc_local_address);
443         if (flags & SC_REMOTE_ADDRESS)
444                 get_address(&p, &len, &kc->kc_remote_address);
445         kc->kc_local_port = get_uint16(&p, &len);
446         kc->kc_remote_port = get_uint16(&p, &len);
447         if (flags & SC_KEYBLOCK)
448                 get_keyblock(&p, &len, &kc->kc_keyblock);
449         if (flags & SC_LOCAL_SUBKEY)
450                 get_keyblock(&p, &len, &kc->kc_local_subkey);
451         if (flags & SC_REMOTE_SUBKEY)
452                 get_keyblock(&p, &len, &kc->kc_remote_subkey);
453         kc->kc_local_seqnumber = get_uint32(&p, &len);
454         kc->kc_remote_seqnumber = get_uint32(&p, &len);
455         kc->kc_keytype = get_uint32(&p, &len);
456         kc->kc_cksumtype = get_uint32(&p, &len);
457         get_data(&p, &len, &kc->kc_source_name);
458         get_data(&p, &len, &kc->kc_target_name);
459         kc->kc_ctx_flags = get_uint32(&p, &len);
460         kc->kc_more_flags = get_uint32(&p, &len);
461         kc->kc_lifetime = get_uint32(&p, &len);
462         /*
463          * Heimdal 1.1 adds the message order stuff.
464          */
465         if (format == KGSS_HEIMDAL_1_1) {
466                 kc->kc_msg_order.km_flags = get_uint32(&p, &len);
467                 kc->kc_msg_order.km_start = get_uint32(&p, &len);
468                 kc->kc_msg_order.km_length = get_uint32(&p, &len);
469                 kc->kc_msg_order.km_jitter_window = get_uint32(&p, &len);
470                 kc->kc_msg_order.km_first_seq = get_uint32(&p, &len);
471                 kc->kc_msg_order.km_elem =
472                         malloc(kc->kc_msg_order.km_jitter_window * sizeof(uint32_t),
473                             M_GSSAPI, M_WAITOK);
474                 for (i = 0; i < kc->kc_msg_order.km_jitter_window; i++)
475                         kc->kc_msg_order.km_elem[i] = get_uint32(&p, &len);
476         } else {
477                 kc->kc_msg_order.km_flags = 0;
478         }
479
480         res = get_keys(kc);
481         if (GSS_ERROR(res))
482                 return (res);
483
484         /*
485          * We don't need these anymore.
486          */
487         delete_keyblock(&kc->kc_keyblock);
488         delete_keyblock(&kc->kc_local_subkey);
489         delete_keyblock(&kc->kc_remote_subkey);
490
491         return (GSS_S_COMPLETE);
492 }
493
494 static void
495 krb5_delete(gss_ctx_id_t ctx, gss_buffer_t output_token)
496 {
497         struct krb5_context *kc = (struct krb5_context *)ctx;
498
499         delete_address(&kc->kc_local_address);
500         delete_address(&kc->kc_remote_address);
501         delete_keyblock(&kc->kc_keyblock);
502         delete_keyblock(&kc->kc_local_subkey);
503         delete_keyblock(&kc->kc_remote_subkey);
504         delete_data(&kc->kc_source_name);
505         delete_data(&kc->kc_target_name);
506         if (kc->kc_msg_order.km_elem)
507                 free(kc->kc_msg_order.km_elem, M_GSSAPI);
508         if (output_token) {
509                 output_token->length = 0;
510                 output_token->value = NULL;
511         }
512         if (kc->kc_tokenkey) {
513                 krb5_free_key(kc->kc_tokenkey);
514                 if (kc->kc_encryptkey) {
515                         krb5_free_key(kc->kc_encryptkey);
516                         krb5_free_key(kc->kc_checksumkey);
517                 } else {
518                         krb5_free_key(kc->kc_send_seal_Ke);
519                         krb5_free_key(kc->kc_send_seal_Ki);
520                         krb5_free_key(kc->kc_send_seal_Kc);
521                         krb5_free_key(kc->kc_send_sign_Kc);
522                         krb5_free_key(kc->kc_recv_seal_Ke);
523                         krb5_free_key(kc->kc_recv_seal_Ki);
524                         krb5_free_key(kc->kc_recv_seal_Kc);
525                         krb5_free_key(kc->kc_recv_sign_Kc);
526                 }
527         }
528         mtx_destroy(&kc->kc_lock);
529 }
530
531 static gss_OID
532 krb5_mech_type(gss_ctx_id_t ctx)
533 {
534
535         return (&krb5_mech_oid);
536 }
537
538 /*
539  * Make a token with the given type and length (the length includes
540  * the TOK_ID), initialising the token header appropriately. Return a
541  * pointer to the TOK_ID of the token.  A new mbuf is allocated with
542  * the framing header plus hlen bytes of space.
543  *
544  * Format is as follows:
545  *
546  *      0x60                    [APPLICATION 0] SEQUENCE
547  *      DER encoded length      length of oid + type + inner token length
548  *      0x06 NN <oid data>      OID of mechanism type
549  *      TT TT                   TOK_ID
550  *      <inner token>           data for inner token
551  *      
552  * 1:           der encoded length
553  */
554 static void *
555 krb5_make_token(char tok_id[2], size_t hlen, size_t len, struct mbuf **mp)
556 {
557         size_t inside_len, len_len, tlen;
558         gss_OID oid = &krb5_mech_oid;
559         struct mbuf *m;
560         uint8_t *p;
561
562         inside_len = 2 + oid->length + len;
563         if (inside_len < 128)
564                 len_len = 1;
565         else if (inside_len < 0x100)
566                 len_len = 2;
567         else if (inside_len < 0x10000)
568                 len_len = 3;
569         else if (inside_len < 0x1000000)
570                 len_len = 4;
571         else
572                 len_len = 5;
573
574         tlen = 1 + len_len + 2 + oid->length + hlen;
575         KASSERT(tlen <= MLEN, ("token head too large"));
576         MGET(m, M_WAITOK, MT_DATA);
577         M_ALIGN(m, tlen);
578         m->m_len = tlen;
579
580         p = (uint8_t *) m->m_data;
581         *p++ = 0x60;
582         switch (len_len) {
583         case 1:
584                 *p++ = inside_len;
585                 break;
586         case 2:
587                 *p++ = 0x81;
588                 *p++ = inside_len;
589                 break;
590         case 3:
591                 *p++ = 0x82;
592                 *p++ = inside_len >> 8;
593                 *p++ = inside_len;
594                 break;
595         case 4:
596                 *p++ = 0x83;
597                 *p++ = inside_len >> 16;
598                 *p++ = inside_len >> 8;
599                 *p++ = inside_len;
600                 break;
601         case 5:
602                 *p++ = 0x84;
603                 *p++ = inside_len >> 24;
604                 *p++ = inside_len >> 16;
605                 *p++ = inside_len >> 8;
606                 *p++ = inside_len;
607                 break;
608         }
609
610         *p++ = 0x06;
611         *p++ = oid->length;
612         bcopy(oid->elements, p, oid->length);
613         p += oid->length;
614
615         p[0] = tok_id[0];
616         p[1] = tok_id[1];
617
618         *mp = m;
619
620         return (p);
621 }
622
623 /*
624  * Verify a token, checking the inner token length and mechanism oid.
625  * pointer to the first byte of the TOK_ID. The length of the
626  * encapsulated data is checked to be at least len bytes; the actual
627  * length of the encapsulated data (including TOK_ID) is returned in
628  * *encap_len.
629  *
630  * If can_pullup is TRUE and the token header is fragmented, we will
631  * rearrange it.
632  *
633  * Format is as follows:
634  *
635  *      0x60                    [APPLICATION 0] SEQUENCE
636  *      DER encoded length      length of oid + type + inner token length
637  *      0x06 NN <oid data>      OID of mechanism type
638  *      TT TT                   TOK_ID
639  *      <inner token>           data for inner token
640  *      
641  * 1:           der encoded length
642  */
643 static void *
644 krb5_verify_token(char tok_id[2], size_t len, struct mbuf **mp,
645     size_t *encap_len, bool_t can_pullup)
646 {
647         struct mbuf *m;
648         size_t tlen, hlen, len_len, inside_len;
649         gss_OID oid = &krb5_mech_oid;
650         uint8_t *p;
651
652         m = *mp;
653         tlen = m_length(m, NULL);
654         if (tlen < 2)
655                 return (NULL);
656
657         /*
658          * Ensure that at least the framing part of the token is
659          * contigous.
660          */
661         if (m->m_len < 2) {
662                 if (can_pullup)
663                         *mp = m = m_pullup(m, 2);
664                 else
665                         return (NULL);
666         }
667
668         p = m->m_data;
669
670         if (*p++ != 0x60)
671                 return (NULL);
672
673         if (*p < 0x80) {
674                 inside_len = *p++;
675                 len_len = 1;
676         } else {
677                 /*
678                  * Ensure there is enough space for the DER encoded length.
679                  */
680                 len_len = (*p & 0x7f) + 1;
681                 if (tlen < len_len + 1)
682                         return (NULL);
683                 if (m->m_len < len_len + 1) {
684                         if (can_pullup)
685                                 *mp = m = m_pullup(m, len_len + 1);
686                         else
687                                 return (NULL);
688                         p = m->m_data + 1;
689                 }
690
691                 switch (*p++) {
692                 case 0x81:
693                         inside_len = *p++;
694                         break;
695
696                 case 0x82:
697                         inside_len = (p[0] << 8) | p[1];
698                         p += 2;
699                         break;
700
701                 case 0x83:
702                         inside_len = (p[0] << 16) | (p[1] << 8) | p[2];
703                         p += 3;
704                         break;
705
706                 case 0x84:
707                         inside_len = (p[0] << 24) | (p[1] << 16)
708                                 | (p[2] << 8) | p[3];
709                         p += 4;
710                         break;
711
712                 default:
713                         return (NULL);
714                 }
715         }
716
717         if (tlen != inside_len + len_len + 1)
718                 return (NULL);
719         if (inside_len < 2 + oid->length + len)
720                 return (NULL);
721
722         /*
723          * Now that we know the value of len_len, we can pullup the
724          * whole header. The header is 1 + len_len + 2 + oid->length +
725          * len bytes.
726          */
727         hlen = 1 + len_len + 2 + oid->length + len;
728         if (m->m_len < hlen) {
729                 if (can_pullup)
730                         *mp = m = m_pullup(m, hlen);
731                 else
732                         return (NULL);
733                 p = m->m_data + 1 + len_len;
734         }
735
736         if (*p++ != 0x06)
737                 return (NULL);
738         if (*p++ != oid->length)
739                 return (NULL);
740         if (bcmp(oid->elements, p, oid->length))
741                 return (NULL);
742         p += oid->length;
743
744         if (p[0] != tok_id[0])
745                 return (NULL);
746
747         if (p[1] != tok_id[1])
748                 return (NULL);
749
750         *encap_len = inside_len - 2 - oid->length;
751
752         return (p);
753 }
754
755 static void
756 krb5_insert_seq(struct krb5_msg_order *mo, uint32_t seq, int index)
757 {
758         int i;
759
760         if (mo->km_length < mo->km_jitter_window)
761                 mo->km_length++;
762
763         for (i = mo->km_length - 1; i > index; i--)
764                 mo->km_elem[i] = mo->km_elem[i - 1];
765         mo->km_elem[index] = seq;
766 }
767
768 /*
769  * Check sequence numbers according to RFC 2743 section 1.2.3.
770  */
771 static OM_uint32
772 krb5_sequence_check(struct krb5_context *kc, uint32_t seq)
773 {
774         OM_uint32 res = GSS_S_FAILURE;
775         struct krb5_msg_order *mo = &kc->kc_msg_order;
776         int check_sequence = mo->km_flags & GSS_C_SEQUENCE_FLAG;
777         int check_replay = mo->km_flags & GSS_C_REPLAY_FLAG;
778         int i;
779
780         mtx_lock(&kc->kc_lock);
781
782         /*
783          * Message is in-sequence with no gap.
784          */
785         if (mo->km_length == 0 || seq == mo->km_elem[0] + 1) {
786                 /*
787                  * This message is received in-sequence with no gaps.
788                  */
789                 krb5_insert_seq(mo, seq, 0);
790                 res = GSS_S_COMPLETE;
791                 goto out;
792         }
793
794         if (seq > mo->km_elem[0]) {
795                 /*
796                  * This message is received in-sequence with a gap.
797                  */
798                 krb5_insert_seq(mo, seq, 0);
799                 if (check_sequence)
800                         res = GSS_S_GAP_TOKEN;
801                 else
802                         res = GSS_S_COMPLETE;
803                 goto out;
804         }
805
806         if (seq < mo->km_elem[mo->km_length - 1]) {
807                 if (check_replay && !check_sequence)
808                         res = GSS_S_OLD_TOKEN;
809                 else
810                         res = GSS_S_UNSEQ_TOKEN;
811                 goto out;
812         }
813
814         for (i = 0; i < mo->km_length; i++) {
815                 if (mo->km_elem[i] == seq) {
816                         res = GSS_S_DUPLICATE_TOKEN;
817                         goto out;
818                 }
819                 if (mo->km_elem[i] < seq) {
820                         /*
821                          * We need to insert this seq here,
822                          */
823                         krb5_insert_seq(mo, seq, i);
824                         if (check_replay && !check_sequence)
825                                 res = GSS_S_COMPLETE;
826                         else
827                                 res = GSS_S_UNSEQ_TOKEN;
828                         goto out;
829                 }
830         }
831
832 out:
833         mtx_unlock(&kc->kc_lock);
834
835         return (res);
836 }
837
838 static uint8_t sgn_alg_des_md5[] = { 0x00, 0x00 };
839 static uint8_t seal_alg_des[] = { 0x00, 0x00 };
840 static uint8_t sgn_alg_des3_sha1[] = { 0x04, 0x00 };
841 static uint8_t seal_alg_des3[] = { 0x02, 0x00 };
842 static uint8_t seal_alg_rc4[] = { 0x10, 0x00 };
843 static uint8_t sgn_alg_hmac_md5[] = { 0x11, 0x00 };
844
845 /*
846  * Return the size of the inner token given the use of the key's
847  * encryption class. For wrap tokens, the length of the padded
848  * plaintext will be added to this.
849  */
850 static size_t
851 token_length(struct krb5_key_state *key)
852 {
853
854         return (16 + key->ks_class->ec_checksumlen);
855 }
856
857 static OM_uint32
858 krb5_get_mic_old(struct krb5_context *kc, struct mbuf *m,
859     struct mbuf **micp, uint8_t sgn_alg[2])
860 {
861         struct mbuf *mlast, *mic, *tm;
862         uint8_t *p, dir;
863         size_t tlen, mlen, cklen;
864         uint32_t seq;
865         char buf[8];
866
867         mlen = m_length(m, &mlast);
868
869         tlen = token_length(kc->kc_tokenkey);
870         p = krb5_make_token("\x01\x01", tlen, tlen, &mic);
871         p += 2;                 /* TOK_ID */
872         *p++ = sgn_alg[0];      /* SGN_ALG */
873         *p++ = sgn_alg[1];
874
875         *p++ = 0xff;            /* filler */
876         *p++ = 0xff;
877         *p++ = 0xff;
878         *p++ = 0xff;
879
880         /*
881          * SGN_CKSUM:
882          *
883          * Calculate the keyed checksum of the token header plus the
884          * message.
885          */
886         cklen = kc->kc_checksumkey->ks_class->ec_checksumlen;
887
888         mic->m_len = p - (uint8_t *) mic->m_data;
889         mic->m_next = m;
890         MGET(tm, M_WAITOK, MT_DATA);
891         tm->m_len = cklen;
892         mlast->m_next = tm;
893
894         krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8,
895             8 + mlen, cklen);
896         bcopy(tm->m_data, p + 8, cklen);
897         mic->m_next = NULL;
898         mlast->m_next = NULL;
899         m_free(tm);
900         
901         /*
902          * SND_SEQ:
903          *
904          * Take the four bytes of the sequence number least
905          * significant first followed by four bytes of direction
906          * marker (zero for initiator and 0xff for acceptor). Encrypt
907          * that data using the SGN_CKSUM as IV. Note: ARC4 wants the
908          * sequence number big-endian.
909          */
910         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
911         if (sgn_alg[0] == 0x11) {
912                 p[0] = (seq >> 24);
913                 p[1] = (seq >> 16);
914                 p[2] = (seq >> 8);
915                 p[3] = (seq >> 0);
916         } else {
917                 p[0] = (seq >> 0);
918                 p[1] = (seq >> 8);
919                 p[2] = (seq >> 16);
920                 p[3] = (seq >> 24);
921         }
922         if (is_initiator(kc)) {
923                 dir = 0;
924         } else {
925                 dir = 0xff;
926         }
927         p[4] = dir;
928         p[5] = dir;
929         p[6] = dir;
930         p[7] = dir;
931         bcopy(p + 8, buf, 8);
932
933         /*
934          * Set the mic buffer to its final size so that the encrypt
935          * can see the SND_SEQ part.
936          */
937         mic->m_len += 8 + cklen;
938         krb5_encrypt(kc->kc_tokenkey, mic, mic->m_len - cklen - 8, 8, buf, 8);
939
940         *micp = mic;
941         return (GSS_S_COMPLETE);
942 }
943
944 static OM_uint32
945 krb5_get_mic_new(struct krb5_context *kc,  struct mbuf *m,
946     struct mbuf **micp)
947 {
948         struct krb5_key_state *key = kc->kc_send_sign_Kc;
949         struct mbuf *mlast, *mic;
950         uint8_t *p;
951         int flags;
952         size_t mlen, cklen;
953         uint32_t seq;
954
955         mlen = m_length(m, &mlast);
956         cklen = key->ks_class->ec_checksumlen;
957
958         KASSERT(16 + cklen <= MLEN, ("checksum too large for an mbuf"));
959         MGET(mic, M_WAITOK, MT_DATA);
960         M_ALIGN(mic, 16 + cklen);
961         mic->m_len = 16 + cklen;
962         p = mic->m_data;
963
964         /* TOK_ID */
965         p[0] = 0x04;
966         p[1] = 0x04;
967
968         /* Flags */
969         flags = 0;
970         if (is_acceptor(kc))
971                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
972         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
973                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
974         p[2] = flags;
975
976         /* Filler */
977         p[3] = 0xff;
978         p[4] = 0xff;
979         p[5] = 0xff;
980         p[6] = 0xff;
981         p[7] = 0xff;
982
983         /* SND_SEQ */
984         p[8] = 0;
985         p[9] = 0;
986         p[10] = 0;
987         p[11] = 0;
988         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
989         p[12] = (seq >> 24);
990         p[13] = (seq >> 16);
991         p[14] = (seq >> 8);
992         p[15] = (seq >> 0);
993
994         /*
995          * SGN_CKSUM:
996          *
997          * Calculate the keyed checksum of the message plus the first
998          * 16 bytes of the token header.
999          */
1000         mlast->m_next = mic;
1001         krb5_checksum(key, 0, m, 0, mlen + 16, cklen);
1002         mlast->m_next = NULL;
1003
1004         *micp = mic;
1005         return (GSS_S_COMPLETE);
1006 }
1007
1008 static OM_uint32
1009 krb5_get_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1010     gss_qop_t qop_req, struct mbuf *m, struct mbuf **micp)
1011 {
1012         struct krb5_context *kc = (struct krb5_context *)ctx;
1013
1014         *minor_status = 0;
1015
1016         if (qop_req != GSS_C_QOP_DEFAULT)
1017                 return (GSS_S_BAD_QOP);
1018
1019         if (time_uptime > kc->kc_lifetime)
1020                 return (GSS_S_CONTEXT_EXPIRED);
1021
1022         switch (kc->kc_tokenkey->ks_class->ec_type) {
1023         case ETYPE_DES_CBC_CRC:
1024                 return (krb5_get_mic_old(kc, m, micp, sgn_alg_des_md5));
1025
1026         case ETYPE_DES3_CBC_SHA1:
1027                 return (krb5_get_mic_old(kc, m, micp, sgn_alg_des3_sha1));
1028
1029         case ETYPE_ARCFOUR_HMAC_MD5:
1030         case ETYPE_ARCFOUR_HMAC_MD5_56:
1031                 return (krb5_get_mic_old(kc, m, micp, sgn_alg_hmac_md5));
1032
1033         default:
1034                 return (krb5_get_mic_new(kc, m, micp));
1035         }
1036
1037         return (GSS_S_FAILURE);
1038 }
1039
1040 static OM_uint32
1041 krb5_verify_mic_old(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic,
1042     uint8_t sgn_alg[2])
1043 {
1044         struct mbuf *mlast, *tm;
1045         uint8_t *p, *tp, dir;
1046         size_t mlen, tlen, elen, miclen;
1047         size_t cklen;
1048         uint32_t seq;
1049
1050         mlen = m_length(m, &mlast);
1051
1052         tlen = token_length(kc->kc_tokenkey);
1053         p = krb5_verify_token("\x01\x01", tlen, &mic, &elen, FALSE);
1054         if (!p)
1055                 return (GSS_S_DEFECTIVE_TOKEN);
1056 #if 0
1057         /*
1058          * Disable this check - heimdal-1.1 generates DES3 MIC tokens
1059          * that are 2 bytes too big.
1060          */
1061         if (elen != tlen)
1062                 return (GSS_S_DEFECTIVE_TOKEN);
1063 #endif
1064         /* TOK_ID */
1065         p += 2;
1066
1067         /* SGN_ALG */
1068         if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1])
1069                 return (GSS_S_DEFECTIVE_TOKEN);
1070         p += 2;
1071
1072         if (p[0] != 0xff || p[1] != 0xff || p[2] != 0xff || p[3] != 0xff)
1073                 return (GSS_S_DEFECTIVE_TOKEN);
1074         p += 4;
1075
1076         /*
1077          * SGN_CKSUM:
1078          *
1079          * Calculate the keyed checksum of the token header plus the
1080          * message.
1081          */
1082         cklen = kc->kc_checksumkey->ks_class->ec_checksumlen;
1083         miclen = mic->m_len;
1084         mic->m_len = p - (uint8_t *) mic->m_data;
1085         mic->m_next = m;
1086         MGET(tm, M_WAITOK, MT_DATA);
1087         tm->m_len = cklen;
1088         mlast->m_next = tm;
1089
1090         krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8,
1091             8 + mlen, cklen);
1092         mic->m_next = NULL;
1093         mlast->m_next = NULL;
1094         if (bcmp(tm->m_data, p + 8, cklen)) {
1095                 m_free(tm);
1096                 return (GSS_S_BAD_SIG);
1097         }
1098
1099         /*
1100          * SND_SEQ:
1101          *
1102          * Take the four bytes of the sequence number least
1103          * significant first followed by four bytes of direction
1104          * marker (zero for initiator and 0xff for acceptor). Encrypt
1105          * that data using the SGN_CKSUM as IV.  Note: ARC4 wants the
1106          * sequence number big-endian.
1107          */
1108         bcopy(p, tm->m_data, 8);
1109         tm->m_len = 8;
1110         krb5_decrypt(kc->kc_tokenkey, tm, 0, 8, p + 8, 8);
1111
1112         tp = tm->m_data;
1113         if (sgn_alg[0] == 0x11) {
1114                 seq = tp[3] | (tp[2] << 8) | (tp[1] << 16) | (tp[0] << 24);
1115         } else {
1116                 seq = tp[0] | (tp[1] << 8) | (tp[2] << 16) | (tp[3] << 24);
1117         }
1118
1119         if (is_initiator(kc)) {
1120                 dir = 0xff;
1121         } else {
1122                 dir = 0;
1123         }
1124         if (tp[4] != dir || tp[5] != dir || tp[6] != dir || tp[7] != dir) {
1125                 m_free(tm);
1126                 return (GSS_S_DEFECTIVE_TOKEN);
1127         }
1128         m_free(tm);
1129
1130         if (kc->kc_msg_order.km_flags &
1131                 (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1132                 return (krb5_sequence_check(kc, seq));
1133         }
1134
1135         return (GSS_S_COMPLETE);
1136 }
1137
1138 static OM_uint32
1139 krb5_verify_mic_new(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic)
1140 {
1141         OM_uint32 res;
1142         struct krb5_key_state *key = kc->kc_recv_sign_Kc;
1143         struct mbuf *mlast;
1144         uint8_t *p;
1145         int flags;
1146         size_t mlen, cklen;
1147         char buf[32];
1148
1149         mlen = m_length(m, &mlast);
1150         cklen = key->ks_class->ec_checksumlen;
1151
1152         KASSERT(mic->m_next == NULL, ("MIC should be contiguous"));
1153         if (mic->m_len != 16 + cklen)
1154                 return (GSS_S_DEFECTIVE_TOKEN);
1155         p = mic->m_data;
1156
1157         /* TOK_ID */
1158         if (p[0] != 0x04)
1159                 return (GSS_S_DEFECTIVE_TOKEN);
1160         if (p[1] != 0x04)
1161                 return (GSS_S_DEFECTIVE_TOKEN);
1162
1163         /* Flags */
1164         flags = 0;
1165         if (is_initiator(kc))
1166                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
1167         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
1168                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
1169         if (p[2] != flags)
1170                 return (GSS_S_DEFECTIVE_TOKEN);
1171
1172         /* Filler */
1173         if (p[3] != 0xff)
1174                 return (GSS_S_DEFECTIVE_TOKEN);
1175         if (p[4] != 0xff)
1176                 return (GSS_S_DEFECTIVE_TOKEN);
1177         if (p[5] != 0xff)
1178                 return (GSS_S_DEFECTIVE_TOKEN);
1179         if (p[6] != 0xff)
1180                 return (GSS_S_DEFECTIVE_TOKEN);
1181         if (p[7] != 0xff)
1182                 return (GSS_S_DEFECTIVE_TOKEN);
1183
1184         /* SND_SEQ */
1185         if (kc->kc_msg_order.km_flags &
1186                 (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1187                 uint32_t seq;
1188                 if (p[8] || p[9] || p[10] || p[11]) {
1189                         res = GSS_S_UNSEQ_TOKEN;
1190                 } else {
1191                         seq = (p[12] << 24) | (p[13] << 16)
1192                                 | (p[14] << 8) | p[15];
1193                         res = krb5_sequence_check(kc, seq);
1194                 }
1195                 if (GSS_ERROR(res))
1196                         return (res);
1197         } else {
1198                 res = GSS_S_COMPLETE;
1199         }
1200
1201         /*
1202          * SGN_CKSUM:
1203          *
1204          * Calculate the keyed checksum of the message plus the first
1205          * 16 bytes of the token header.
1206          */
1207         m_copydata(mic, 16, cklen, buf);
1208         mlast->m_next = mic;
1209         krb5_checksum(key, 0, m, 0, mlen + 16, cklen);
1210         mlast->m_next = NULL;
1211         if (bcmp(buf, p + 16, cklen)) {
1212                 return (GSS_S_BAD_SIG);
1213         }
1214
1215         return (GSS_S_COMPLETE);
1216 }
1217
1218 static OM_uint32
1219 krb5_verify_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1220     struct mbuf *m, struct mbuf *mic, gss_qop_t *qop_state)
1221 {
1222         struct krb5_context *kc = (struct krb5_context *)ctx;
1223
1224         *minor_status = 0;
1225         if (qop_state)
1226                 *qop_state = GSS_C_QOP_DEFAULT;
1227
1228         if (time_uptime > kc->kc_lifetime)
1229                 return (GSS_S_CONTEXT_EXPIRED);
1230
1231         switch (kc->kc_tokenkey->ks_class->ec_type) {
1232         case ETYPE_DES_CBC_CRC:
1233                 return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des_md5));
1234
1235         case ETYPE_ARCFOUR_HMAC_MD5:
1236         case ETYPE_ARCFOUR_HMAC_MD5_56:
1237                 return (krb5_verify_mic_old(kc, m, mic, sgn_alg_hmac_md5));
1238
1239         case ETYPE_DES3_CBC_SHA1:
1240                 return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des3_sha1));
1241
1242         default:
1243                 return (krb5_verify_mic_new(kc, m, mic));
1244         }
1245
1246         return (GSS_S_FAILURE);
1247 }
1248
1249 static OM_uint32
1250 krb5_wrap_old(struct krb5_context *kc, int conf_req_flag,
1251     struct mbuf **mp, int *conf_state,
1252     uint8_t sgn_alg[2], uint8_t seal_alg[2])
1253 {
1254         struct mbuf *m, *mlast, *tm, *cm, *pm;
1255         size_t mlen, tlen, padlen, datalen;
1256         uint8_t *p, dir;
1257         size_t cklen;
1258         uint8_t buf[8];
1259         uint32_t seq;
1260
1261         /*
1262          * How many trailing pad bytes do we need?
1263          */
1264         m = *mp;
1265         mlen = m_length(m, &mlast);
1266         tlen = kc->kc_tokenkey->ks_class->ec_msgblocklen;
1267         padlen = tlen - (mlen % tlen);
1268
1269         /*
1270          * The data part of the token has eight bytes of random
1271          * confounder prepended and followed by up to eight bytes of
1272          * padding bytes each of which is set to the number of padding
1273          * bytes.
1274          */
1275         datalen = mlen + 8 + padlen;
1276         tlen = token_length(kc->kc_tokenkey);
1277
1278         p = krb5_make_token("\x02\x01", tlen, datalen + tlen, &tm);
1279         p += 2;                 /* TOK_ID */
1280         *p++ = sgn_alg[0];      /* SGN_ALG */
1281         *p++ = sgn_alg[1];
1282         if (conf_req_flag) {
1283                 *p++ = seal_alg[0]; /* SEAL_ALG */
1284                 *p++ = seal_alg[1];
1285         } else {
1286                 *p++ = 0xff;    /* SEAL_ALG = none */
1287                 *p++ = 0xff;
1288         }
1289
1290         *p++ = 0xff;            /* filler */
1291         *p++ = 0xff;
1292
1293         /*
1294          * Copy the padded message data.
1295          */
1296         if (M_LEADINGSPACE(m) >= 8) {
1297                 m->m_data -= 8;
1298                 m->m_len += 8;
1299         } else {
1300                 MGET(cm, M_WAITOK, MT_DATA);
1301                 cm->m_len = 8;
1302                 cm->m_next = m;
1303                 m = cm;
1304         }
1305         arc4rand(m->m_data, 8, 0);
1306         if (M_TRAILINGSPACE(mlast) >= padlen) {
1307                 memset(mlast->m_data + mlast->m_len, padlen, padlen);
1308                 mlast->m_len += padlen;
1309         } else {
1310                 MGET(pm, M_WAITOK, MT_DATA);
1311                 memset(pm->m_data, padlen, padlen);
1312                 pm->m_len = padlen;
1313                 mlast->m_next = pm;
1314                 mlast = pm;
1315         }
1316         tm->m_next = m;
1317
1318         /*
1319          * SGN_CKSUM:
1320          *
1321          * Calculate the keyed checksum of the token header plus the
1322          * padded message. Fiddle with tm->m_len so that we only
1323          * checksum the 8 bytes of head that we care about.
1324          */
1325         cklen = kc->kc_checksumkey->ks_class->ec_checksumlen;
1326         tlen = tm->m_len;
1327         tm->m_len = p - (uint8_t *) tm->m_data;
1328         MGET(cm, M_WAITOK, MT_DATA);
1329         cm->m_len = cklen;
1330         mlast->m_next = cm;
1331         krb5_checksum(kc->kc_checksumkey, 13, tm, tm->m_len - 8,
1332             datalen + 8, cklen);
1333         tm->m_len = tlen;
1334         mlast->m_next = NULL;
1335         bcopy(cm->m_data, p + 8, cklen);
1336         m_free(cm);
1337
1338         /*
1339          * SND_SEQ:
1340          *
1341          * Take the four bytes of the sequence number least
1342          * significant first (most signficant first for ARCFOUR)
1343          * followed by four bytes of direction marker (zero for
1344          * initiator and 0xff for acceptor). Encrypt that data using
1345          * the SGN_CKSUM as IV.
1346          */
1347         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
1348         if (sgn_alg[0] == 0x11) {
1349                 p[0] = (seq >> 24);
1350                 p[1] = (seq >> 16);
1351                 p[2] = (seq >> 8);
1352                 p[3] = (seq >> 0);
1353         } else {
1354                 p[0] = (seq >> 0);
1355                 p[1] = (seq >> 8);
1356                 p[2] = (seq >> 16);
1357                 p[3] = (seq >> 24);
1358         }
1359         if (is_initiator(kc)) {
1360                 dir = 0;
1361         } else {
1362                 dir = 0xff;
1363         }
1364         p[4] = dir;
1365         p[5] = dir;
1366         p[6] = dir;
1367         p[7] = dir;
1368         krb5_encrypt(kc->kc_tokenkey, tm, p - (uint8_t *) tm->m_data,
1369             8, p + 8, 8);
1370
1371         if (conf_req_flag) {
1372                 /*
1373                  * Encrypt the padded message with an IV of zero for
1374                  * DES and DES3, or an IV of the sequence number in
1375                  * big-endian format for ARCFOUR.
1376                  */
1377                 if (seal_alg[0] == 0x10) {
1378                         buf[0] = (seq >> 24);
1379                         buf[1] = (seq >> 16);
1380                         buf[2] = (seq >> 8);
1381                         buf[3] = (seq >> 0);
1382                         krb5_encrypt(kc->kc_encryptkey, m, 0, datalen,
1383                             buf, 4);
1384                 } else {
1385                         krb5_encrypt(kc->kc_encryptkey, m, 0, datalen,
1386                             NULL, 0);
1387                 }
1388         }
1389
1390         if (conf_state)
1391                 *conf_state = conf_req_flag;
1392
1393         *mp = tm;
1394         return (GSS_S_COMPLETE);
1395 }
1396
1397 static OM_uint32
1398 krb5_wrap_new(struct krb5_context *kc, int conf_req_flag,
1399     struct mbuf **mp, int *conf_state)
1400 {
1401         struct krb5_key_state *Ke = kc->kc_send_seal_Ke;
1402         struct krb5_key_state *Ki = kc->kc_send_seal_Ki;
1403         struct krb5_key_state *Kc = kc->kc_send_seal_Kc;
1404         const struct krb5_encryption_class *ec = Ke->ks_class;
1405         struct mbuf *m, *mlast, *tm;
1406         uint8_t *p;
1407         int flags, EC;
1408         size_t mlen, blen, mblen, cklen, ctlen;
1409         uint32_t seq;
1410         static char zpad[32];
1411
1412         m = *mp;
1413         mlen = m_length(m, &mlast);
1414
1415         blen = ec->ec_blocklen;
1416         mblen = ec->ec_msgblocklen;
1417         cklen = ec->ec_checksumlen;
1418
1419         if (conf_req_flag) {
1420                 /*
1421                  * For sealed messages, we need space for 16 bytes of
1422                  * header, blen confounder, plaintext, padding, copy
1423                  * of header and checksum.
1424                  *
1425                  * We pad to mblen (which may be different from
1426                  * blen). If the encryption class is using CTS, mblen
1427                  * will be one (i.e. no padding required).
1428                  */
1429                 if (mblen > 1)
1430                         EC = mlen % mblen;
1431                 else
1432                         EC = 0;
1433                 ctlen = blen + mlen + EC + 16;
1434
1435                 /*
1436                  * Put initial header and confounder before the
1437                  * message.
1438                  */
1439                 M_PREPEND(m, 16 + blen, M_WAITOK);
1440
1441                 /*
1442                  * Append padding + copy of header and checksum. Try
1443                  * to fit this into the end of the original message,
1444                  * otherwise allocate a trailer.
1445                  */
1446                 if (M_TRAILINGSPACE(mlast) >= EC + 16 + cklen) {
1447                         tm = NULL;
1448                         mlast->m_len += EC + 16 + cklen;
1449                 } else {
1450                         MGET(tm, M_WAITOK, MT_DATA);
1451                         tm->m_len = EC + 16 + cklen;
1452                         mlast->m_next = tm;
1453                 }
1454         } else {
1455                 /*
1456                  * For unsealed messages, we need 16 bytes of header
1457                  * plus space for the plaintext and a checksum. EC is
1458                  * set to the checksum size. We leave space in tm for
1459                  * a copy of the header - this will be trimmed later.
1460                  */
1461                 M_PREPEND(m, 16, M_WAITOK);
1462
1463                 MGET(tm, M_WAITOK, MT_DATA);
1464                 tm->m_len = cklen + 16;
1465                 mlast->m_next = tm;
1466                 ctlen = 0;
1467                 EC = cklen;
1468         }
1469
1470         p = m->m_data;
1471
1472         /* TOK_ID */
1473         p[0] = 0x05;
1474         p[1] = 0x04;
1475
1476         /* Flags */
1477         flags = 0;
1478         if (conf_req_flag)
1479                 flags = GSS_TOKEN_SEALED;
1480         if (is_acceptor(kc))
1481                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
1482         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
1483                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
1484         p[2] = flags;
1485
1486         /* Filler */
1487         p[3] = 0xff;
1488
1489         /* EC + RRC - set to zero initially */
1490         p[4] = 0;
1491         p[5] = 0;
1492         p[6] = 0;
1493         p[7] = 0;
1494
1495         /* SND_SEQ */
1496         p[8] = 0;
1497         p[9] = 0;
1498         p[10] = 0;
1499         p[11] = 0;
1500         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
1501         p[12] = (seq >> 24);
1502         p[13] = (seq >> 16);
1503         p[14] = (seq >> 8);
1504         p[15] = (seq >> 0);
1505
1506         if (conf_req_flag) {
1507                 /*
1508                  * Encrypt according to RFC 4121 section 4.2 and RFC
1509                  * 3961 section 5.3. Note: we don't generate tokens
1510                  * with RRC values other than zero. If we did, we
1511                  * should zero RRC in the copied header.
1512                  */
1513                 arc4rand(p + 16, blen, 0);
1514                 if (EC) {
1515                         m_copyback(m, 16 + blen + mlen, EC, zpad);
1516                 }
1517                 m_copyback(m, 16 + blen + mlen + EC, 16, p);
1518
1519                 krb5_checksum(Ki, 0, m, 16, ctlen, cklen);
1520                 krb5_encrypt(Ke, m, 16, ctlen, NULL, 0);
1521         } else {
1522                 /*
1523                  * The plaintext message is followed by a checksum of
1524                  * the plaintext plus a version of the header where EC
1525                  * and RRC are set to zero. Also, the original EC must
1526                  * be our checksum size.
1527                  */
1528                 bcopy(p, tm->m_data, 16);
1529                 krb5_checksum(Kc, 0, m, 16, mlen + 16, cklen);
1530                 tm->m_data += 16;
1531                 tm->m_len -= 16;
1532         }
1533
1534         /*
1535          * Finally set EC to its actual value
1536          */
1537         p[4] = EC >> 8;
1538         p[5] = EC;
1539
1540         *mp = m;
1541         return (GSS_S_COMPLETE);
1542 }
1543
1544 static OM_uint32
1545 krb5_wrap(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1546     int conf_req_flag, gss_qop_t qop_req,
1547     struct mbuf **mp, int *conf_state)
1548 {
1549         struct krb5_context *kc = (struct krb5_context *)ctx;
1550
1551         *minor_status = 0;
1552         if (conf_state)
1553                 *conf_state = 0;
1554
1555         if (qop_req != GSS_C_QOP_DEFAULT)
1556                 return (GSS_S_BAD_QOP);
1557
1558         if (time_uptime > kc->kc_lifetime)
1559                 return (GSS_S_CONTEXT_EXPIRED);
1560
1561         switch (kc->kc_tokenkey->ks_class->ec_type) {
1562         case ETYPE_DES_CBC_CRC:
1563                 return (krb5_wrap_old(kc, conf_req_flag,
1564                         mp, conf_state, sgn_alg_des_md5, seal_alg_des));
1565
1566         case ETYPE_ARCFOUR_HMAC_MD5:
1567         case ETYPE_ARCFOUR_HMAC_MD5_56:
1568                 return (krb5_wrap_old(kc, conf_req_flag,
1569                         mp, conf_state, sgn_alg_hmac_md5, seal_alg_rc4));
1570
1571         case ETYPE_DES3_CBC_SHA1:
1572                 return (krb5_wrap_old(kc, conf_req_flag,
1573                         mp, conf_state, sgn_alg_des3_sha1, seal_alg_des3));
1574
1575         default:
1576                 return (krb5_wrap_new(kc, conf_req_flag, mp, conf_state));
1577         }
1578
1579         return (GSS_S_FAILURE);
1580 }
1581
1582 static void
1583 m_trim(struct mbuf *m, int len)
1584 {
1585         struct mbuf *n;
1586         int off;
1587
1588         n = m_getptr(m, len, &off);
1589         if (n) {
1590                 n->m_len = off;
1591                 if (n->m_next) {
1592                         m_freem(n->m_next);
1593                         n->m_next = NULL;
1594                 }
1595         }
1596 }
1597
1598 static OM_uint32
1599 krb5_unwrap_old(struct krb5_context *kc, struct mbuf **mp, int *conf_state,
1600     uint8_t sgn_alg[2], uint8_t seal_alg[2])
1601 {
1602         OM_uint32 res;
1603         struct mbuf *m, *mlast, *hm, *cm;
1604         uint8_t *p, dir;
1605         size_t mlen, tlen, elen, datalen, padlen;
1606         size_t cklen;
1607         uint8_t buf[32];
1608         uint32_t seq;
1609         int i, conf;
1610
1611         m = *mp;
1612         mlen = m_length(m, &mlast);
1613
1614         tlen = token_length(kc->kc_tokenkey);
1615         cklen = kc->kc_tokenkey->ks_class->ec_checksumlen;
1616
1617         p = krb5_verify_token("\x02\x01", tlen, &m, &elen, TRUE);
1618         *mp = m;
1619         if (!p)
1620                 return (GSS_S_DEFECTIVE_TOKEN);
1621         datalen = elen - tlen;
1622
1623         /*
1624          * Trim the framing header first to make life a little easier
1625          * later.
1626          */
1627         m_adj(m, p - (uint8_t *) m->m_data);
1628
1629         /* TOK_ID */
1630         p += 2;
1631
1632         /* SGN_ALG */
1633         if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1])
1634                 return (GSS_S_DEFECTIVE_TOKEN);
1635         p += 2;
1636
1637         /* SEAL_ALG */
1638         if (p[0] == seal_alg[0] && p[1] == seal_alg[1])
1639                 conf = 1;
1640         else if (p[0] == 0xff && p[1] == 0xff)
1641                 conf = 0;
1642         else
1643                 return (GSS_S_DEFECTIVE_TOKEN);
1644         p += 2;
1645
1646         if (p[0] != 0xff || p[1] != 0xff)
1647                 return (GSS_S_DEFECTIVE_TOKEN);
1648         p += 2;
1649
1650         /*
1651          * SND_SEQ:
1652          *
1653          * Take the four bytes of the sequence number least
1654          * significant first (most significant for ARCFOUR) followed
1655          * by four bytes of direction marker (zero for initiator and
1656          * 0xff for acceptor). Encrypt that data using the SGN_CKSUM
1657          * as IV.
1658          */
1659         krb5_decrypt(kc->kc_tokenkey, m, 8, 8, p + 8, 8);
1660         if (sgn_alg[0] == 0x11) {
1661                 seq = p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24);
1662         } else {
1663                 seq = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
1664         }
1665
1666         if (is_initiator(kc)) {
1667                 dir = 0xff;
1668         } else {
1669                 dir = 0;
1670         }
1671         if (p[4] != dir || p[5] != dir || p[6] != dir || p[7] != dir)
1672                 return (GSS_S_DEFECTIVE_TOKEN);
1673
1674         if (kc->kc_msg_order.km_flags &
1675             (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1676                 res = krb5_sequence_check(kc, seq);
1677                 if (GSS_ERROR(res))
1678                         return (res);
1679         } else {
1680                 res = GSS_S_COMPLETE;
1681         }
1682
1683         /*
1684          * If the token was encrypted, decode it in-place.
1685          */
1686         if (conf) {
1687                 /*
1688                  * Decrypt the padded message with an IV of zero for
1689                  * DES and DES3 or an IV of the big-endian encoded
1690                  * sequence number for ARCFOUR.
1691                  */
1692                 if (seal_alg[0] == 0x10) {
1693                         krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen,
1694                             datalen, p, 4);
1695                 } else {
1696                         krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen,
1697                             datalen, NULL, 0);
1698                 }
1699         }
1700         if (conf_state)
1701                 *conf_state = conf;
1702
1703         /*
1704          * Check the trailing pad bytes.
1705          */
1706         KASSERT(mlast->m_len > 0, ("Unexpected empty mbuf"));
1707         padlen = mlast->m_data[mlast->m_len - 1];
1708         m_copydata(m, tlen + datalen - padlen, padlen, buf);
1709         for (i = 0; i < padlen; i++) {
1710                 if (buf[i] != padlen) {
1711                         return (GSS_S_DEFECTIVE_TOKEN);
1712                 }
1713         }
1714
1715         /*
1716          * SGN_CKSUM:
1717          *
1718          * Calculate the keyed checksum of the token header plus the
1719          * padded message. We do a little mbuf surgery to trim out the
1720          * parts we don't want to checksum.
1721          */
1722         hm = m;
1723         *mp = m = m_split(m, 16 + cklen, M_WAITOK);
1724         mlast = m_last(m);
1725         hm->m_len = 8;
1726         hm->m_next = m;
1727         MGET(cm, M_WAITOK, MT_DATA);
1728         cm->m_len = cklen;
1729         mlast->m_next = cm;
1730
1731         krb5_checksum(kc->kc_checksumkey, 13, hm, 0, datalen + 8, cklen);
1732         hm->m_next = NULL;
1733         mlast->m_next = NULL;
1734
1735         if (bcmp(cm->m_data, hm->m_data + 16, cklen)) {
1736                 m_freem(hm);
1737                 m_free(cm);
1738                 return (GSS_S_BAD_SIG);
1739         }
1740         m_freem(hm);
1741         m_free(cm);
1742
1743         /*
1744          * Trim off the confounder and padding.
1745          */
1746         m_adj(m, 8);
1747         if (mlast->m_len >= padlen) {
1748                 mlast->m_len -= padlen;
1749         } else {
1750                 m_trim(m, datalen - 8 - padlen);
1751         }
1752
1753         *mp = m;
1754         return (res);
1755 }
1756
1757 static OM_uint32
1758 krb5_unwrap_new(struct krb5_context *kc, struct mbuf **mp, int *conf_state)
1759 {
1760         OM_uint32 res;
1761         struct krb5_key_state *Ke = kc->kc_recv_seal_Ke;
1762         struct krb5_key_state *Ki = kc->kc_recv_seal_Ki;
1763         struct krb5_key_state *Kc = kc->kc_recv_seal_Kc;
1764         const struct krb5_encryption_class *ec = Ke->ks_class;
1765         struct mbuf *m, *mlast, *hm, *cm;
1766         uint8_t *p, *pp;
1767         int sealed, flags, EC, RRC;
1768         size_t blen, cklen, ctlen, mlen, plen, tlen;
1769         char buf[32], buf2[32];
1770
1771         m = *mp;
1772         mlen = m_length(m, &mlast);
1773
1774         if (mlen <= 16)
1775                 return (GSS_S_DEFECTIVE_TOKEN);
1776         if (m->m_len < 16) {
1777                 m = m_pullup(m, 16);
1778                 *mp = m;
1779         }
1780         p = m->m_data;
1781
1782         /* TOK_ID */
1783         if (p[0] != 0x05)
1784                 return (GSS_S_DEFECTIVE_TOKEN);
1785         if (p[1] != 0x04)
1786                 return (GSS_S_DEFECTIVE_TOKEN);
1787
1788         /* Flags */
1789         sealed = p[2] & GSS_TOKEN_SEALED;
1790         flags = sealed;
1791         if (is_initiator(kc))
1792                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
1793         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
1794                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
1795         if (p[2] != flags)
1796                 return (GSS_S_DEFECTIVE_TOKEN);
1797
1798         /* Filler */
1799         if (p[3] != 0xff)
1800                 return (GSS_S_DEFECTIVE_TOKEN);
1801
1802         /* EC + RRC */
1803         EC = (p[4] << 8) + p[5];
1804         RRC = (p[6] << 8) + p[7];
1805
1806         /* SND_SEQ */
1807         if (kc->kc_msg_order.km_flags &
1808                 (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1809                 uint32_t seq;
1810                 if (p[8] || p[9] || p[10] || p[11]) {
1811                         res = GSS_S_UNSEQ_TOKEN;
1812                 } else {
1813                         seq = (p[12] << 24) | (p[13] << 16)
1814                                 | (p[14] << 8) | p[15];
1815                         res = krb5_sequence_check(kc, seq);
1816                 }
1817                 if (GSS_ERROR(res))
1818                         return (res);
1819         } else {
1820                 res = GSS_S_COMPLETE;
1821         }
1822
1823         /*
1824          * Separate the header before dealing with RRC. We only need
1825          * to keep the header if the message isn't encrypted.
1826          */
1827         if (sealed) {
1828                 hm = NULL;
1829                 m_adj(m, 16);
1830         } else {
1831                 hm = m;
1832                 *mp = m = m_split(m, 16, M_WAITOK);
1833                 mlast = m_last(m);
1834         }
1835
1836         /*
1837          * Undo the effects of RRC by rotating left.
1838          */
1839         if (RRC > 0) {
1840                 struct mbuf *rm;
1841                 size_t rlen;
1842
1843                 rlen = mlen - 16;
1844                 if (RRC <= sizeof(buf) && m->m_len >= rlen) {
1845                         /*
1846                          * Simple case, just rearrange the bytes in m.
1847                          */
1848                         bcopy(m->m_data, buf, RRC);
1849                         bcopy(m->m_data + RRC, m->m_data, rlen - RRC);
1850                         bcopy(buf, m->m_data + rlen - RRC, RRC);
1851                 } else {
1852                         /*
1853                          * More complicated - rearrange the mbuf
1854                          * chain.
1855                          */
1856                         rm = m;
1857                         *mp = m = m_split(m, RRC, M_WAITOK);
1858                         m_cat(m, rm);
1859                         mlast = rm;
1860                 }
1861         }
1862
1863         blen = ec->ec_blocklen;
1864         cklen = ec->ec_checksumlen;
1865         if (sealed) {
1866                 /*
1867                  * Decrypt according to RFC 4121 section 4.2 and RFC
1868                  * 3961 section 5.3. The message must be large enough
1869                  * for a blocksize confounder, at least one block of
1870                  * cyphertext and a checksum.
1871                  */
1872                 if (mlen < 16 + 2*blen + cklen)
1873                         return (GSS_S_DEFECTIVE_TOKEN);
1874
1875                 ctlen = mlen - 16 - cklen;
1876                 krb5_decrypt(Ke, m, 0, ctlen, NULL, 0);
1877
1878                 /*
1879                  * The size of the plaintext is ctlen minus blocklen
1880                  * (for the confounder), 16 (for the copy of the token
1881                  * header) and EC (for the filler). The actual
1882                  * plaintext starts after the confounder.
1883                  */
1884                 plen = ctlen - blen - 16 - EC;
1885                 pp = p + 16 + blen;
1886
1887                 /*
1888                  * Checksum the padded plaintext.
1889                  */
1890                 m_copydata(m, ctlen, cklen, buf);
1891                 krb5_checksum(Ki, 0, m, 0, ctlen, cklen);
1892                 m_copydata(m, ctlen, cklen, buf2);
1893
1894                 if (bcmp(buf, buf2, cklen))
1895                         return (GSS_S_BAD_SIG);
1896
1897                 /*
1898                  * Trim the message back to just plaintext.
1899                  */
1900                 m_adj(m, blen);
1901                 tlen = 16 + EC + cklen;
1902                 if (mlast->m_len >= tlen) {
1903                         mlast->m_len -= tlen;
1904                 } else {
1905                         m_trim(m, plen);
1906                 }
1907         } else {
1908                 /*
1909                  * The plaintext message is followed by a checksum of
1910                  * the plaintext plus a version of the header where EC
1911                  * and RRC are set to zero. Also, the original EC must
1912                  * be our checksum size.
1913                  */
1914                 if (mlen < 16 + cklen || EC != cklen)
1915                         return (GSS_S_DEFECTIVE_TOKEN);
1916
1917                 /*
1918                  * The size of the plaintext is simply the message
1919                  * size less header and checksum. The plaintext starts
1920                  * right after the header (which we have saved in hm).
1921                  */
1922                 plen = mlen - 16 - cklen;
1923
1924                 /*
1925                  * Insert a copy of the header (with EC and RRC set to
1926                  * zero) between the plaintext message and the
1927                  * checksum.
1928                  */
1929                 p = hm->m_data;
1930                 p[4] = p[5] = p[6] = p[7] = 0;
1931
1932                 cm = m_split(m, plen, M_WAITOK);
1933                 mlast = m_last(m);
1934                 m->m_next = hm;
1935                 hm->m_next = cm;
1936
1937                 bcopy(cm->m_data, buf, cklen);
1938                 krb5_checksum(Kc, 0, m, 0, plen + 16, cklen);
1939                 if (bcmp(cm->m_data, buf, cklen))
1940                         return (GSS_S_BAD_SIG);
1941
1942                 /*
1943                  * The checksum matches, discard all buf the plaintext.
1944                  */
1945                 mlast->m_next = NULL;
1946                 m_freem(hm);
1947         }
1948
1949         if (conf_state)
1950                 *conf_state = (sealed != 0);
1951
1952         return (res);
1953 }
1954
1955 static OM_uint32
1956 krb5_unwrap(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1957     struct mbuf **mp, int *conf_state, gss_qop_t *qop_state)
1958 {
1959         struct krb5_context *kc = (struct krb5_context *)ctx;
1960         OM_uint32 maj_stat;
1961
1962         *minor_status = 0;
1963         if (qop_state)
1964                 *qop_state = GSS_C_QOP_DEFAULT;
1965         if (conf_state)
1966                 *conf_state = 0;
1967
1968         if (time_uptime > kc->kc_lifetime)
1969                 return (GSS_S_CONTEXT_EXPIRED);
1970
1971         switch (kc->kc_tokenkey->ks_class->ec_type) {
1972         case ETYPE_DES_CBC_CRC:
1973                 maj_stat = krb5_unwrap_old(kc, mp, conf_state,
1974                         sgn_alg_des_md5, seal_alg_des);
1975                 break;
1976
1977         case ETYPE_ARCFOUR_HMAC_MD5:
1978         case ETYPE_ARCFOUR_HMAC_MD5_56:
1979                 maj_stat = krb5_unwrap_old(kc, mp, conf_state,
1980                         sgn_alg_hmac_md5, seal_alg_rc4);
1981                 break;
1982
1983         case ETYPE_DES3_CBC_SHA1:
1984                 maj_stat = krb5_unwrap_old(kc, mp, conf_state,
1985                         sgn_alg_des3_sha1, seal_alg_des3);
1986                 break;
1987
1988         default:
1989                 maj_stat = krb5_unwrap_new(kc, mp, conf_state);
1990                 break;
1991         }
1992
1993         if (GSS_ERROR(maj_stat)) {
1994                 m_freem(*mp);
1995                 *mp = NULL;
1996         }
1997
1998         return (maj_stat);
1999 }
2000
2001 static OM_uint32
2002 krb5_wrap_size_limit(gss_ctx_id_t ctx, OM_uint32 *minor_status,
2003     int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size,
2004     OM_uint32 *max_input_size)
2005 {
2006         struct krb5_context *kc = (struct krb5_context *)ctx;
2007         const struct krb5_encryption_class *ec;
2008         OM_uint32 overhead;
2009
2010         *minor_status = 0;
2011         *max_input_size = 0;
2012
2013         if (qop_req != GSS_C_QOP_DEFAULT)
2014                 return (GSS_S_BAD_QOP);
2015
2016         ec = kc->kc_tokenkey->ks_class;
2017         switch (ec->ec_type) {
2018         case ETYPE_DES_CBC_CRC:
2019         case ETYPE_DES3_CBC_SHA1:
2020         case ETYPE_ARCFOUR_HMAC_MD5: 
2021         case ETYPE_ARCFOUR_HMAC_MD5_56:
2022                 /*
2023                  * up to 5 bytes for [APPLICATION 0] SEQUENCE
2024                  * 2 + krb5 oid length
2025                  * 8 bytes of header
2026                  * 8 bytes of confounder
2027                  * maximum of 8 bytes of padding
2028                  * checksum
2029                  */
2030                 overhead = 5 + 2 + krb5_mech_oid.length;
2031                 overhead += 8 + 8 + ec->ec_msgblocklen;
2032                 overhead += ec->ec_checksumlen;
2033                 break;
2034
2035         default:
2036                 if (conf_req_flag) {
2037                         /*
2038                          * 16 byts of header
2039                          * blocklen bytes of confounder
2040                          * up to msgblocklen - 1 bytes of padding
2041                          * 16 bytes for copy of header
2042                          * checksum
2043                          */
2044                         overhead = 16 + ec->ec_blocklen;
2045                         overhead += ec->ec_msgblocklen - 1;
2046                         overhead += 16;
2047                         overhead += ec->ec_checksumlen;
2048                 } else {
2049                         /*
2050                          * 16 bytes of header plus checksum.
2051                          */
2052                         overhead = 16 + ec->ec_checksumlen;
2053                 }
2054         }
2055
2056         *max_input_size = req_output_size - overhead;
2057
2058         return (GSS_S_COMPLETE);
2059 }
2060
2061 static kobj_method_t krb5_methods[] = {
2062         KOBJMETHOD(kgss_init,           krb5_init),
2063         KOBJMETHOD(kgss_import,         krb5_import),
2064         KOBJMETHOD(kgss_delete,         krb5_delete),
2065         KOBJMETHOD(kgss_mech_type,      krb5_mech_type),
2066         KOBJMETHOD(kgss_get_mic,        krb5_get_mic),
2067         KOBJMETHOD(kgss_verify_mic,     krb5_verify_mic),
2068         KOBJMETHOD(kgss_wrap,           krb5_wrap),
2069         KOBJMETHOD(kgss_unwrap,         krb5_unwrap),
2070         KOBJMETHOD(kgss_wrap_size_limit, krb5_wrap_size_limit),
2071         { 0, 0 }
2072 };
2073
2074 static struct kobj_class krb5_class = {
2075         "kerberosv5",
2076         krb5_methods,
2077         sizeof(struct krb5_context)
2078 };
2079
2080 /*
2081  * Kernel module glue
2082  */
2083 static int
2084 kgssapi_krb5_modevent(module_t mod, int type, void *data)
2085 {
2086
2087         switch (type) {
2088         case MOD_LOAD:
2089                 kgss_install_mech(&krb5_mech_oid, "kerberosv5", &krb5_class);
2090                 break;
2091
2092         case MOD_UNLOAD:
2093                 kgss_uninstall_mech(&krb5_mech_oid);
2094                 break;
2095         }
2096
2097
2098         return (0);
2099 }
2100 static moduledata_t kgssapi_krb5_mod = {
2101         "kgssapi_krb5",
2102         kgssapi_krb5_modevent,
2103         NULL,
2104 };
2105 DECLARE_MODULE(kgssapi_krb5, kgssapi_krb5_mod, SI_SUB_VFS, SI_ORDER_ANY);
2106 MODULE_DEPEND(kgssapi_krb5, kgssapi, 1, 1, 1);
2107 MODULE_DEPEND(kgssapi_krb5, crypto, 1, 1, 1);
2108 MODULE_DEPEND(kgssapi_krb5, rc4, 1, 1, 1);
2109 MODULE_VERSION(kgssapi_krb5, 1);